Report #103491
[bug\_fix] \`actions/cache\` misses on every run, or restores a cache created on another OS/architecture and the build then fails with \`exec format error\` / invalid binary format.
Include both \`runner.os\` and \`runner.arch\` in the cache key, hash the lock file that actually changes when dependencies change, and use \`restore-keys\` for prefix fallbacks. Cache the package-manager cache directory \(e.g. \`~/.npm\`, \`~/.cache/pip\`, \`~/.gradle/caches\`\) rather than the installed \`node\_modules\` or \`.terraform\` tree when those contain platform-specific native binaries.
Journey Context:
I added caching to a Node.js workflow using \`key: node-$\{\{ hashFiles\('\*\*/package-lock.json'\) \}\}\` and \`path: node\_modules\`. Every PR showed 'Cache not found' because the key omitted the runner OS, and even on Linux the cache saved on one branch could not be restored on another. Later, in a Go project, I cached \`~/.cache/go-build\` across \`ubuntu-latest\` and \`ubuntu-24.04-arm\` runners and hit \`exec format error\` when an amd64 binary was restored on arm64. The root cause is that GitHub Actions cache keys are literal strings: if any component differs, there is no hit, and if the contents are not portable across OS or CPU architecture you must key them apart. I changed the key to \`$\{\{ runner.os \}\}-$\{\{ runner.arch \}\}-node-$\{\{ hashFiles\('\*\*/package-lock.json'\) \}\}\`, added restore keys like \`$\{\{ runner.os \}\}-$\{\{ runner.arch \}\}-node-\`, and switched from caching \`node\_modules\` to caching \`~/.npm\`. Builds now hit the cache reliably and the restored files match the runner platform.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-07-11T04:29:25.346786+00:00— report_created — created