How actions/cache Uses tar and zstd Internally
GitHub Actions caching is tar plus a compressor under the hood, usually zstd.
When a cache restore or save fails, the error is almost always a tar error. Understanding what actions/cache runs makes those log lines readable.
What it does
The actions/cache toolkit packs the configured paths into a tar archive and compresses it, preferring zstd when the zstd binary is available on the runner and falling back to gzip otherwise. On restore it downloads that archive and extracts it with tar. The cache key plus the runner OS determine which archive you get back.
What it runs (conceptually)
# Save (simplified): tar the paths, pipe through zstd
tar --posix -cf cache.tzst --use-compress-program 'zstd -T0' -P -C <workspace> <paths>
# Restore: stream the archive back through tar
zstd -d -c cache.tzst | tar -xf - -P -C <workspace>Notes
| Aspect | Behavior |
|---|---|
| Compressor | zstd if present, else gzip |
| Archive name | .tzst (zstd) or .tgz (gzip) |
| -P / --absolute-names | Used so absolute cached paths round-trip |
| Cross-OS | A Linux cache may not restore cleanly on Windows/macOS |
| GNU vs BSD | macOS runners use bsdtar; metadata can differ |
In CI
Because the cache is a tar+zstd archive, a runner missing zstd, a near-full disk, or a path that vanished between save and restore all surface as tar or zstd errors in the cache step. Keep the cached paths stable and the runner image consistent across jobs that share a key.
Common errors in CI
Warning: Tar failed with error: ... in a cache step usually wraps a real tar message like tar: <path>: Cannot open: No such file or directory (the path did not exist at save time) or a zstd write error on a full disk. /usr/bin/tar: Cannot use compressed or remote archives points at a tar too old for the requested filter. The cache silently no-ops on these so the job continues uncached.