Skip to content
Latchkey LogoLatchkey home

An artifact with this name already exists in GitHub Actions

The error an artifact with this name already exists is a 409 from the artifact service, and it has been the intended behavior of GitHub Actions since version 4 of actions/upload-artifact: a name is unique within a run, and an artifact cannot be rewritten once finalized. The second upload is not overwriting the first and is not being merged into it; it is refused.

What changed at version 4 and which input or sub-action replaces each older habit
Three version 3 habits, three version 4 replacements. The uniqueness is per run, not per job, which is the part testing usually reveals last.

What this error means

One leg of a matrix uploads and the rest fail, or a second upload in the same job fails while the first passed. Whichever leg got there first survives, so the failing job changes between runs and the whole thing reads as flaky. The log above the error looks healthy: a file count, a valid name, a valid root directory. The failure line does not name the artifact it collided with, a gap reported against the action itself.

Actions log, quoted from upload-artifact#634
Error: Failed to CreateArtifact: Received non-retryable error: Failed request: (409) Conflict: an artifact with this name already exists on the workflow run

A minimal workflow that produces it

This file is written for this page and has never been run. It is the shape the version 4 migration document uses as its own example of what stopped working: three matrix legs, each uploading its own file under one shared artifact name. Under version 3 that produced one artifact holding three files. Under version 4 the first leg creates it and the other two get a 409.

.github/workflows/ci.yml (illustrative)
name: ci
on:
  push:

jobs:
  build:
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - run: echo "hello from ${{ matrix.os }}" > file.txt
      - uses: actions/upload-artifact@v7
        with:
          name: my-artifact
          path: file.txt

Common causes

Every leg of a matrix uploads the same name

The dominant cause, and the one the migration document leads with. Under version 3 this was the normal way to collect output from several platforms into one artifact. Under version 4 it is a race, and which leg wins varies, which is why this is usually first reported as a flaky matrix rather than a duplicated name.

The same name is uploaded twice in one run, in different jobs

Because uniqueness is per run rather than per job, splitting the uploads apart does not separate the names. Two jobs that both upload under coverage collide exactly as if they were two steps in one job, and moving one into its own job is the most common failed fix for this error.

A shared or third-party action uploads a name you do not control

Composite and marketplace actions often upload a diagnostic bundle under a fixed name. Call one twice in a run and the second call fails inside somebody else's code. The Microsoft action cited below is exactly that: it offered no way to set the artifact name, so every workflow calling it twice broke.

overwrite is set but is looking at the wrong name

On version 7, direct upload with archive: false derives the name from the file while overwrite is reported to still delete by the name input. The delete removes nothing, the create hits the existing artifact, and you get this error despite having asked for overwriting. The practical answer is to avoid combining those two inputs.

How to fix it

Put the matrix value in the name

The corrected version of the illustrative workflow above, and the change the migration document makes in its own diff. Every leg now uploads a distinct artifact and none races any other. It is the right fix for most matrices, because the artifacts really are different.

.github/workflows/ci.yml, corrected (illustrative)
      - uses: actions/upload-artifact@v7
        with:
          name: my-artifact-${{ matrix.os }}
          path: file.txt
          if-no-files-found: error

Download them back as one directory

Splitting the upload only moves the problem if the consumer still expects one artifact. The download side has two inputs for this: pattern selects the set by prefix and merge-multiple puts them in one directory instead of one subdirectory each. It pairs with the fix above as written.

.github/workflows/ci.yml, corrected (illustrative)
  collect:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v8
        with:
          path: all
          pattern: my-artifact-*
          merge-multiple: true
      - run: ls -R all

Merge into one real artifact when you need a single download

If something outside the workflow downloads the artifact, a set of names is not enough and you want one object. The merge sub-action does that in an extra job: it pulls the matching artifacts, combines them and uploads one. It costs a round trip of the data, which is why the pattern download is better when a later job is the only consumer.

.github/workflows/ci.yml (illustrative)
  merge:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/upload-artifact/merge@v7
        with:
          name: all-my-files
          pattern: my-artifact-*

Use overwrite only where last writer wins is what you mean

Republishing one artifact from one job, such as a preview build that should reflect the latest push within a run, is what this input was added for. Do not reach for it to silence a matrix: the legs delete one another and the survivor is whichever finished last. The replacement is a new artifact with a new id, so any link captured earlier goes stale.

.github/workflows/ci.yml (illustrative)
      - uses: actions/upload-artifact@v7
        with:
          name: preview
          path: dist
          overwrite: true
          if-no-files-found: error

What version 4 changed, and when each replacement arrived

Version 4 landed on 14 December 2023 as a rewrite of the artifact backend. Its release notes call it a major update with breaking changes, adding that artifacts created with version 3 and below are not compatible and that uploads and downloads must use the same major versions. Immutability is the piece that produces this error: the migration document says that in version 4 artifacts are immutable unless deleted.

The replacements did not all arrive at once, which is worth knowing if you are reading advice from early 2024 and wondering why an input does not exist. The dates below come from the release notes, checked today against the GitHub releases API.

Everything after version 4.4.0 is runtime and packaging rather than behavior. Version 5 added Node 24 support, version 6 made Node 24 the default and raised the minimum Actions runner to 2.327.1, and version 7 added direct uploads and moved to ESM. None of them changed how names collide.

VersionReleasedWhat it changed about names
v4.0.014 December 2023Artifacts became immutable and names unique within a run
v4.2.018 January 2024Added overwrite, which deletes the old artifact first
v4.3.023 January 2024Added the merge sub-action for combining artifacts
v4.4.030 August 2024Excluded hidden files by default, unrelated to naming

Unique per run, not per job

The obvious reading of the message is that the collision is within a job, and it is not. The reporter of one widely linked case tested exactly that, splitting each upload into its own job, and reported back that it made no difference: the name has to be unique across the whole run. That is why moving a duplicated upload into a separate job does not help.

Two inputs sit either side of the rule. overwrite: true deletes any artifact with that name before uploading, which gives last-writer-wins, and the migration document adds the consequence that matters: this creates an entirely new artifact with a different id from the previous one. Set it on a matrix and the legs delete each other in whatever order they finish.

The other direction is the merge sub-action, which downloads a set of artifacts and re-uploads them as one, at the cost of an extra job and a round trip of the data. One open edge on version 7: with archive: false the name comes from the uploaded file rather than the name input, and a report says overwrite still deletes by name.

Why there is no recorded run on this page

A 409 here is a correct answer to a request for something the service does not allow. It is deterministic and documented as intended, and re-running produces it again in whichever leg loses the race. Nothing in it is transient and there is nothing for a runner to repair: the fix is a different name, and that lives in the workflow file.

How to prevent it

  • Derive every artifact name from the thing that makes it unique, usually the matrix value.
  • Treat artifact names as unique across the run, not the job, when reviewing a workflow.
  • Give any shared or composite action that uploads an artifact a name input.
  • Reserve overwrite for a single deliberate republish and never for a matrix.

Frequently asked questions

Why does upload-artifact say a name already exists in a matrix?
Because version 4 made artifacts immutable and names unique within a run, so only the first leg can create that name and the rest get a 409. Version 3 merged those uploads into one artifact, which is why this appears on the first run after an upgrade. Put the matrix value in the name.
Are GitHub Actions artifact names unique per job or per run?
Per run. Moving a duplicated upload into its own job does not avoid the conflict, which is the most common failed fix for this error. One widely linked report worked through exactly that, splitting each upload into a separate job before concluding that the name has to be unique across the whole workflow run.
What does overwrite: true do in actions/upload-artifact?
It deletes any existing artifact with that name before uploading the new one, so the last writer wins. The migration document adds the part that catches people: the result is an entirely new artifact with a different id, so anything that captured the old id or url now points at something gone. Available since version 4.2.0.
How do I combine matrix artifacts into one artifact now?
Upload one name per leg, then add a job running the merge sub-action with a pattern matching them. It downloads the set, combines it and uploads one artifact under your name. If the only consumer is a later job in the same run, download by pattern with merge-multiple instead.

Related guides

References

Name per leg, then merge: a third job on every run. Latchkey runs it at $0.0025/min at 2 vCPU. Start free → 30-day trial · No credit card