[bug] Artifact overwrite doesn't always work
What happened?
I run the following:
Run actions/upload-artifact@v4
with:
name: coverage-132-python_services_AI_PE
path: coverage.xml
overwrite: true
retention-days: 15
if-no-files-found: warn
compression-level: 6
I get:
With the provided path, there will be 1 file uploaded
Artifact 'coverage-132-python_services_AI_PE' (ID: 1554547722) deleted
Artifact name is valid!
Root directory input is valid!
Beginning upload of artifact content to blob storage
Uploaded bytes 2459
Finished uploading artifact content to blob storage!
SHA256 hash of uploaded artifact zip is ade371acd3b3694e3719d4f7e6a5e87d3d9f03ee3a9c4a7170c6f22ea588a488
Finalizing artifact upload
Artifact coverage-132-python_services_AI_PE.zip successfully finalized. Artifact ID 1554567367
Artifact coverage-132-python_services_AI_PE has been successfully uploaded! Final size is 2459 bytes. Artifact ID is 1554567367
I rerun it:
Run actions/upload-artifact@v4
with:
name: coverage-132-python_services_AI_PE
path: coverage.xml
overwrite: true
retention-days: 15
if-no-files-found: warn
compression-level: 6
With the provided path, there will be 1 file uploaded
Artifact name is valid!
Root directory input is valid!
Beginning upload of artifact content to blob storage
Uploaded bytes 2459
Finished uploading artifact content to blob storage!
SHA256 hash of uploaded artifact zip is 66e88e2c255466f590048ad87d1ad78adc4547825a47df05bbab9a95dc10b56e
Finalizing artifact upload
Artifact coverage-132-python_services_AI_PE.zip successfully finalized. Artifact ID 155586
Artifact coverage-132-python_services_AI_PE has been successfully uploaded! Final size is 2459 bytes. Artifact ID is 1555861812
Why on earth doesn't the file get overwritten in both cases? What am I doing wrong?
What did you expect to happen?
I expected the file to be overwritten in both cases
How can we reproduce it?
Yesterday it worked but I cannot get it to work again, so I cannot go back to a state where it works as expected
Anything else we need to know?
No response
What version of the action are you using?
Tried both 4 and 4.3.1
What are your runner environments?
linux
Are you on GitHub Enterprise Server? If so, what version?
No response
Same. overwrite: true doesn't prevent conflict from happening.
It seems to be non-deterministic; a re-run fixes it.
My money is on read-modify-write.
Will we ever improve?
My money is on read-modify-write
Will we ever improve?
https://github.com/actions/upload-artifact/blob/552bf3722c16e81001aea7db72d8cedf64eb5f68/src/upload/upload-artifact.ts#L11
Though FWIW, I don't think this is sole source of the problem. I suspect@actions/artifact.
I seem to be hitting this issue while trying to setup dependency workflows (in my case, I don't actually want the job to be run multiple times, but it doesn't seem like there's a way to avoid it if I want to have clean dependency chains... anyway that's separate from this issue).
I'm guessing the issue has to do with some race condition on when the failing upload detects the upstream file for deletion as mentioned above...
Run actions/upload-artifact@v4
with:
name: zlib
path: deploy
retention-days: 1
overwrite: true
if-no-files-found: warn
compression-level: 6
include-hidden-files: false
/usr/bin/docker exec 7878ccf80f356a0485880cabb5e592859e334a2541d9cd2cccd8d98cd60e0dba sh -c "cat /etc/*release | grep ^ID"
With the provided path, there will be 5 files uploaded
Artifact 'zlib' (ID: 2524238627) deleted
Artifact name is valid!
Root directory input is valid!
Error: Failed to CreateArtifact: Received non-retryable error: Failed request: (409) Conflict: an artifact with this name already exists on the workflow run
However, within the same workflow that happens to be building zlib multiple times, I see it being uploaded and overwritten
Run actions/upload-artifact@v4
with:
name: zlib
path: deploy
retention-days: 1
overwrite: true
if-no-files-found: warn
compression-level: 6
include-hidden-files: false
/usr/bin/docker exec 1daa0646bd0883f142c275350ebfc586e090b1bb164f77e9f3470f27c909c1a4 sh -c "cat /etc/*release | grep ^ID"
With the provided path, there will be 5 files uploaded
Artifact name is valid!
Root directory input is valid!
Beginning upload of artifact content to blob storage
Uploaded bytes 93169
Finished uploading artifact content to blob storage!
SHA256 hash of uploaded artifact zip is 00a74a1a47e9fe4a25bab31731849ae428e6825d03bdc44d19995e52092a0ae4
Finalizing artifact upload
Artifact zlib.zip successfully finalized. Artifact ID 2524238649
Artifact zlib has been successfully uploaded! Final size is 93169 bytes. Artifact ID is 2524238649
Run actions/upload-artifact@v4
with:
name: zlib
path: deploy
retention-days: 1
overwrite: true
if-no-files-found: warn
compression-level: 6
include-hidden-files: false
/usr/bin/docker exec 1e47a5b439cf1d636a4ace56dc1cfcc017d7ff82ec9638119b136d5d6cd7bd80 sh -c "cat /etc/*release | grep ^ID"
With the provided path, there will be 5 files uploaded
Artifact 'zlib' (ID: 2524238582) deleted
Artifact name is valid!
Root directory input is valid!
Beginning upload of artifact content to blob storage
Uploaded bytes 93154
Finished uploading artifact content to blob storage!
SHA256 hash of uploaded artifact zip is 87e03cef015147a0b593a126b7164598d9c72fe3813c09d29c3bf7bffdaaef84
Finalizing artifact upload
Artifact zlib.zip successfully finalized. Artifact ID 2524238627
Artifact zlib has been successfully uploaded! Final size is 93154 bytes. Artifact ID is 2524238627
Seems pretty inconsistent.
This has made GH Actions unusable for a project for me: https://github.com/test262-fyi/test262.fyi. Pretty sure this is some kind of race condition because this action's overwrite trying to work around the upstream library changes and there is no nice solution other than making an alternative upload function there. Usually I could just downgrade to work around this but GH crashes CI when I do that because it is deprecated so there is just no solution for the moment other than rewriting on my end to avoid GH's bug.
Is it expected behavior that uploading an artifact with overwrite: true does not delete the previous file:
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: file-name
retention-days: 300
overwrite: true
path: path/to/file
and then
ipankr@home % curl -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer token" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/owner/repo/actions/artifacts?name=file-name"
{
"total_count": 2,
"artifacts": [
{
"id": 3131874511,
"node_id": "MDg6QXJ0aWZhYMTMxODc0NTEx",
"name": "file-name",
"size_in_bytes": 101809,
"url": "https://api.github.com/repos/owner/repo/actions/artifacts/3131874511",
"archive_download_url": "https://api.github.com/repos/owner/repo/actions/artifacts/3131874511/zip",
"expired": false,
"digest": "sha256:7093cd071c5376b8aba726c11cb2dfa2ad37084bb6df551af6d3eaaa3d3d0cd5",
"created_at": "2025-05-15T14:26:14Z",
"updated_at": "2025-05-15T14:26:14Z",
"expires_at": "2025-06-14T14:24:56Z",
"workflow_run": {
"id": 15047539372,
"repository_id": 919935657,
"head_repository_id": 919935657,
"head_branch": "main",
"head_sha": "e21ffbfa5f62412a7492e69096eee56e810ca7c1"
}
},
{
"id": 3131406611,
"node_id": "MDg6QXJ0aWZhYMTMxNDA2NjEx",
"name": "file-name",
"size_in_bytes": 101815,
"url": "https://api.github.com/repos/owner/repo/actions/artifacts/3131406611",
"archive_download_url": "https://api.github.com/repos/owner/repo/actions/artifacts/3131406611/zip",
"expired": false,
"digest": "sha256:fe498acac3a7f7ef2cb932817fd2b292c62ad6eda5c9361f54f4d82b8e66340d",
"created_at": "2025-05-15T13:33:39Z",
"updated_at": "2025-05-15T13:33:39Z",
"expires_at": "2025-06-14T13:32:21Z",
"workflow_run": {
"id": 15046324628,
"repository_id": 919935657,
"head_repository_id": 919935657,
"head_branch": "main",
"head_sha": "99e3cbfcec0da6ec6655e24d21265f69d8232b24"
}
},
]
}
I'm in the same boat as you, I thought the overwrite option would mean deleting other artifact with the same name in the repository but it doesn't.
I would say it is not an obvious behavior.