Skip to content
Latchkey

GitHub Actions Artifact Expired - "artifact has expired" on Download

A download of an older artifact fails because it has passed its retention period and was deleted. Artifacts are retained for a configurable window (90 days by default, less if overridden) and then removed.

What this error means

Re-running an old workflow, or downloading an artifact from a past run, fails because the artifact no longer exists - it expired and was garbage-collected.

Actions log
Error: Unable to download artifact(s): Artifact has expired
# the run is older than the retention period

Diagnose it: was the cache hit, and was it the right one?

Cache bugs split into three shapes and they need different fixes: the cache never saved, it saved but the key never matches on restore, or it restored a stale entry through a restore-keys prefix and is now poisoning the build. The step output tells you which one you have.

.github/workflows/ci.yml
- uses: actions/cache@v4
  id: cache
  with:
    path: ~/.npm
    key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-npm-

- name: What happened
  run: |
    echo "exact hit: ${{ steps.cache.outputs.cache-hit }}"
    echo "key used:  ${{ steps.cache.outputs.cache-matched-key }}"

Common causes

Retention period elapsed

Artifacts are deleted after their retention window. By default this is 90 days, but org/repo settings or retention-days can shorten it.

Relying on artifacts for long-term storage

Using build artifacts as a durable store fails once they expire. Artifacts are for short-lived run outputs, not archival.

How to fix it

Set retention-days to what you need

Raise retention-days (up to the repo/org maximum) for artifacts you must keep longer, within limits.

.github/workflows/ci.yml
- uses: actions/upload-artifact@v4
  with:
    name: build
    path: dist
    retention-days: 30

Use durable storage for long-lived outputs

  1. Push artifacts you need to keep to a release, package registry, or object storage (S3/GCS).
  2. Do not depend on cross-run artifact downloads for runs older than retention.
  3. Regenerate the artifact by re-running the producing job when needed.

Cache limits that produce confusing failures

  • Repository cache is capped at 10 GB. Past that, GitHub evicts least-recently-used entries, so a large cache can silently stop persisting.
  • Caches are scoped by branch. A cache written on a feature branch is not visible to another feature branch, only to its base and its own descendants.
  • An entry not read for 7 days is evicted, so a rarely-run workflow effectively never has a warm cache.
  • Restoring a cache built for a different tool version is worse than a cold start, because you get a corrupted tree instead of a clean install. Always include the tool version in the key.

How to prevent it

  • Treat artifacts as short-lived run outputs, not archives.
  • Set retention-days deliberately for artifacts you reuse.
  • Publish durable outputs to releases or object storage.

Frequently asked questions

What causes GitHub Actions artifact expired?
There are 2 common causes: retention period elapsed and relying on artifacts for long-term storage. Artifacts are deleted after their retention window.
How do I fix GitHub Actions artifact expired?
There are 2 fixes depending on which cause you have: set retention-days to what you need and use durable storage for long-lived outputs. Work through them in order, since the first is the most common.
What does GitHub Actions artifact expired actually mean?
Re-running an old workflow, or downloading an artifact from a past run, fails because the artifact no longer exists - it expired and was garbage-collected.
How do I stop GitHub Actions artifact expired happening again?
Treat artifacts as short-lived run outputs, not archives. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card