现象
日志出现 Cache not found for input keys;每次运行都重新安装依赖;保存成功但下次仍 miss;主分支能命中而 PR 不能。
诊断
先看 workflow 里的 key 表达式,再列出仓库缓存:
grep -n -B3 -A8 'actions/cache' .github/workflows/ci.yml
gh cache list --limit 30
gh run view $(gh run list --limit 1 --json databaseId --jq '.[0].databaseId') --log | grep -iE 'cache (restored|saved|not found)|reserve cache'
key 里出现 github.run_id、github.sha 或时间戳,永远不可能命中。hashFiles('pnpm-lock.yaml') 相对于 workspace 计算,monorepo 必须写实际路径,否则哈希的是空集合。日志会打印解析后的 key 与恢复结果:not found 且 Failed to reserve cache 多为配额或作用域问题,而不是语法错误。
根因
恢复的 key 在作业可见的作用域内不存在。缓存不可变,并按分支、PR merge ref 与缓存版本隔离;key 不稳定、路径错误、缓存写在其他分支或超出 10 GB 被 LRU 淘汰,都会导致 miss。
修复
使用固定前缀加 lockfile 哈希,并加 restore-keys 兜底;缓存包管理器 store 而不是 node_modules:
- uses: actions/cache@v4
with:
path: ~/.local/share/pnpm/store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
不要在 key 中放 run_id 或 sha;需要主动失效时改版本后缀。PR 的缓存按 merge ref 隔离,不要把 PR 自己写入的缓存当作下一次运行的前提,也不要缓存密钥或 .env 文件。
验证
同一分支连续运行两次且不改 lockfile,第二次日志应出现 Cache restored from key 且安装步骤明显变短;修改 lockfile 后应先 miss、保存,再下一次命中。gh cache list 中能看到对应条目。