mediumIntermediateUSE#cache#actions-cache#slow-build#dependency

Actions cache miss every run - slow builds from scratch

Build step duration doubled - dependencies reinstalled every run

Likely source:performanceconfiguration

Focused incident mode — strips away everything but this runbook.

Symptoms

  • Build step duration doubled - dependencies reinstalled every run
  • actions/cache step logs 'Cache not found for key: <key>'
  • Package manager installs node_modules or pip from scratch each time

Actions cache keys are exact-match by default. A key with github.sha or github.run_id will miss every time. Use hashFiles on lockfiles for reliable cache hits.

Evidence to grab

Collect these artifacts before you change anything — they prove (or rule out) each cause.

  • Cache restore log output

    gh run view <RUN_ID> --log | grep -A3 'actions/cache'
  • Cache key configuration

    cat .github/workflows/<file>.yml | grep -A5 'key:'

Diagnostic flow

Run the steps in order, marking each claim confirmed or refuted. The evidence you gather feeds the ranked causes below.

Guided decision tree is ready.

Steps with commands, expected output, and pass/fail branches.

Ranked root causes

Evidence checklist

  • key: ${{ runner.os }}-npm-${{ github.run_id }}
  • Cache is unique per run and never matches any previous run

Confirm before fixing

cat .github/workflows/<file>.yml | grep 'key:' | head -3
READ

Read the cache key

Fix

sed -i 's/${{ github.run_id }}/${{ hashFiles("**\/package-lock.json") }}/' .github/workflows/<file>.yml
CHANGE

Replace run_id with a file-hash-based key

Resolution runbook

Apply from top to bottom after the cause is confirmed. Review every command before running it — risk tags are shown on each.

1
gh run view <RUN_ID> --log | grep -A10 'Cache'
READ

Read the cache restore output

2
cat .github/workflows/<file>.yml | grep -B2 -A15 'key:'
READ

Inspect the key and restore-keys

3
gh cache list --repo <OWNER/REPO>
READ

List existing caches to see what keys exist

4
gh cache delete <CACHE_KEY> --repo <OWNER/REPO>
DESTRUCTIVE

Delete stale caches if needed

Prevention

  • Key on hashFiles of the lockfile (package-lock.json, go.sum, requirements.txt), never on run_id or sha.
  • Always provide restore-keys with a broad prefix for fallback matching.
  • Keep cache paths consistent with the package manager's actual cache directory.
  • Set a reasonable cache-size limit (default 10 GB per repo) to avoid eviction.

Commands marked READ CHANGE DESTRUCTIVE — never run DESTRUCTIVE commands against production data you cannot restore. Copy → verify → execute.