CircleCI Server 4.9 and later save caches with zstd compression. A current task-agent restores those archives. An older task-agent still treats the file as gzip, and the restore fails with gzip: invalid header. The cache is not corrupt. The reader is too old.
A job on a current executor and a job on an old self-hosted runner can download the same cache key and then diverge. The current job prints Extracting using zstd and continues. The old job stops in restore_cache on the gzip error.
Which versions
Server 4.9.0 is the release that uses zstd for caches by default. The 4.9 release notes describe this as improved caching with zstd compression. Patch releases on the 4.9 line, including 4.9.6, keep that behavior.
The task-agent is what reads the archive. Container runner and machine runner download that binary and can keep an older copy. Docker and machine executors that shipped with Server 4.9 already include a task-agent that understands zstd. There is no runner version number that marks the first good release. Confirm the binary from the job log instead.
CircleCI Cloud started writing zstd caches on 25 June 2025. A self-hosted runner that still has an older task-agent fails the same way when it restores a cache saved by a current agent.
What to check
On the failing job, open restore_cache. gzip: invalid header means the file started with a zstd header and the agent opened it as gzip.
On a job that uses a current agent, the same restore prints:
Extracting using zstd
The save side of a current agent prints Using zstd compression. The first lines of the job include Build Agent version. After you update the runner, that version should change, and the next restore on that resource class should print Extracting using zstd.
What to do
Update container runner or machine runner to a current release, then restart the runner process so it drops a cached task-agent binary. The next job on that resource class should restore the existing cache. You do not need a new cache key.
If the restore still prints gzip: invalid header, the resource class is still launching the old task-agent. Send the Build Agent version line from that job.
