actions/cache cross-OS cache restore mismatch in CI
A cache key that omits runner.os lets a Linux cache restore onto Windows or macOS (and vice versa). The restored archive holds platform-specific binaries and path layouts that do not work on the other OS, causing native-module errors or tar failures.
What this error means
After a cache hit, the build fails with native module ABI errors, "is not a valid Win32 application", missing binaries, or a tar error, because the restored cache came from a different operating system.
Cache restored from key: deps-7f3a9c
Error: \\?\D:\a\app\node_modules\fsevents\build\Release\fse.node is not a valid Win32 application.Common causes
The cache key has no OS component
A key like deps-${{ hashFiles(...) }} is shared across all matrix OSes, so whichever job saves first poisons the others with its platform binaries.
Restore-keys prefix matches across OSes
A shared restore-keys prefix without runner.os lets a prefix hit pull another OS's cache.
How to fix it
Always include runner.os in key and restore-keys
- Add
${{ runner.os }}to bothkeyand everyrestore-keysprefix. - Re-run so each OS only ever restores its own cache.
- Confirm the native errors disappear after the keys are OS-scoped.
key: deps-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
deps-${{ runner.os }}-Add arch too when runners differ
On mixed architectures (for example arm64 vs x64 macOS), add ${{ runner.arch }} so a cache never crosses CPU architectures either.
How to prevent it
- Scope every cache key by
runner.os(andrunner.archwhen relevant). - Never share a dependency cache across operating systems.
- Keep matrix legs isolated with distinct key prefixes.