Fix: GitHub Actions Artifacts Not Working — Upload Fails, Download Empty, or Artifact Not Found
Quick Answer
How to fix GitHub Actions artifact issues — upload-artifact path patterns, download-artifact across jobs, retention days, artifact name conflicts, and the v3 to v4 migration.
The Problem
upload-artifact completes but the artifact is empty or not found:
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
# "Warning: No files were found with the provided path: dist/"Or download-artifact in a later job fails:
download-job:
needs: build-job
steps:
- uses: actions/download-artifact@v4
with:
name: build-output
# Error: Unable to find artifact 'build-output'Or artifact names conflict and overwrite each other in a matrix build:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/upload-artifact@v4
with:
name: test-results # Same name for all matrix jobs — conflict
path: results/Why This Happens
Artifacts in GitHub Actions have several non-obvious behaviors:
- Paths are relative to the workspace —
path: dist/refers to$GITHUB_WORKSPACE/dist/. If your build step runs in a different directory or the output path differs, no files match. - Artifacts are scoped to the workflow run — a job can only download artifacts uploaded in the same workflow run, unless you use the
run-idparameter. - Matrix jobs share the artifact namespace — if two matrix jobs upload artifacts with the same name, one overwrites the other (in v3) or the upload fails (in v4 with
overwrite: false). - v3 vs v4 breaking changes —
actions/upload-artifact@v4andactions/download-artifact@v4have different defaults and no longer support downloading all artifacts without a name.
Fix 1: Verify the Upload Path Exists
The most common cause of empty artifacts is the path not existing at upload time:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: npm run build # Outputs to dist/
# Debug: list what's in the workspace
- name: List files
run: ls -la dist/ || echo "dist/ does not exist"
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
if-no-files-found: error # Fail the step if nothing matched (default: warn)Common path issues:
# WRONG — path inside a subdirectory, but workspace is the root
- run: cd myapp && npm run build # Output goes to myapp/dist/
- uses: actions/upload-artifact@v4
with:
path: dist/ # Looks for $GITHUB_WORKSPACE/dist/ — wrong!
# CORRECT — include the subdirectory in the path
- uses: actions/upload-artifact@v4
with:
path: myapp/dist/
# Or set working-directory for the build step:
- name: Build
working-directory: myapp
run: npm run build
- uses: actions/upload-artifact@v4
with:
path: myapp/dist/ # Still relative to GITHUB_WORKSPACEUse glob patterns to capture multiple files:
- uses: actions/upload-artifact@v4
with:
name: test-results
path: |
coverage/
test-results/*.xml
**/*.log
if-no-files-found: errorFix 2: Download Artifacts Correctly Across Jobs
Artifacts are only available after the uploading job completes. Use needs: to declare the dependency:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
deploy:
runs-on: ubuntu-latest
needs: build # Waits for 'build' to complete
steps:
- uses: actions/download-artifact@v4
with:
name: build-output
path: dist/ # Downloads to this directory
- name: Deploy
run: |
ls dist/ # Verify download succeeded
./deploy.shDownload all artifacts from the run:
# actions/download-artifact@v4 — download all artifacts
- uses: actions/download-artifact@v4
# No 'name' parameter — downloads all artifacts
# Each artifact goes into a subdirectory named after the artifact
- name: List downloaded artifacts
run: ls -la # Shows: build-output/, test-results/, etc.Download an artifact from a different workflow run:
- uses: actions/download-artifact@v4
with:
name: build-output
run-id: ${{ github.event.workflow_run.id }} # Specific run ID
github-token: ${{ secrets.GITHUB_TOKEN }}Fix 3: Fix Matrix Build Artifact Name Conflicts
In matrix builds, each job must upload to a unique artifact name:
# WRONG — all matrix jobs overwrite the same artifact
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- run: npm test
- uses: actions/upload-artifact@v4
with:
name: test-results # Same name — conflict in v4, overwrite in v3
path: results/
# CORRECT — unique name per matrix combination
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- run: npm test
- uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.os }} # Unique per job
path: results/
merge-results:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
pattern: test-results-* # Download all matching artifacts
merge-multiple: true # Merge into a single directory
path: all-results/Fix 4: Migrate from v3 to v4
actions/upload-artifact@v4 and actions/download-artifact@v4 have breaking changes from v3:
# v3 — download all artifacts merges into current directory
- uses: actions/download-artifact@v3
# Downloads all artifacts, potentially overwriting files with same names
# v4 — download all artifacts creates subdirectories
- uses: actions/download-artifact@v4
# Each artifact in its own subdirectory named after the artifact
# v3 — artifact names could be duplicated across matrix jobs (last writer wins)
# v4 — duplicate artifact names fail by default
- uses: actions/upload-artifact@v4
with:
name: my-artifact
path: output/
overwrite: true # Allow overwriting — restores v3 behaviorKey v4 changes:
# v4: 'path' when downloading now specifies the destination directory
- uses: actions/download-artifact@v4
with:
name: build-output
path: downloaded/ # Files go into downloaded/
# v4: use 'pattern' for wildcard matching (replaces downloading without 'name')
- uses: actions/download-artifact@v4
with:
pattern: build-* # Match multiple artifact names
merge-multiple: false # Each artifact in its own subdirectory (default)Fix 5: Set Retention and Size Limits
Artifacts have default retention and size limits that cause unexpected expiry or upload failures:
- uses: actions/upload-artifact@v4
with:
name: large-build
path: dist/
retention-days: 7 # Keep for 7 days (default: 90 for public, varies for private)
compression-level: 9 # 0-9, higher = smaller file, slower upload (default: 6)Size limits by plan:
- Free: 500 MB per artifact, 1 GB total per run
- Pro/Team: 2 GB per artifact
- Enterprise: configurable
Reduce artifact size:
# Exclude unnecessary files
- uses: actions/upload-artifact@v4
with:
name: build-output
path: |
dist/
!dist/**/*.map # Exclude source maps
!dist/**/*.test.* # Exclude test files
compression-level: 9Fix 6: Use Artifacts for Job Communication
Artifacts are the standard way to pass data between jobs in a workflow:
jobs:
generate-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- id: set-matrix
run: |
MATRIX=$(cat config/test-matrix.json)
echo "matrix=$MATRIX" >> $GITHUB_OUTPUT
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 1 # Short-lived — only needed for this run
test:
needs: build
runs-on: ubuntu-latest
strategy:
matrix:
shard: [1, 2, 3, 4]
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- run: npm test -- --shard=${{ matrix.shard }}/4
- uses: actions/upload-artifact@v4
with:
name: test-results-shard-${{ matrix.shard }}
path: test-results/
if-no-files-found: error
report:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
pattern: test-results-shard-*
merge-multiple: true
path: all-test-results/
- name: Generate report
run: npx junit-merge all-test-results/**/*.xml -o combined.xml
- uses: actions/upload-artifact@v4
with:
name: test-report
path: combined.xml
retention-days: 30Still Not Working?
Artifact not found in a workflow_run event — when a triggered workflow tries to download artifacts from the parent workflow using the workflow_run event, you need to pass github-token and run-id explicitly. The artifact is only accessible after the parent workflow completes.
“Artifact storage quota has been reached” — your repository or organization has hit the artifact storage limit. Reduce retention-days for existing artifacts, delete old artifacts via the GitHub API (DELETE /repos/{owner}/{repo}/actions/artifacts/{artifact_id}), or increase the retention policy for your plan. Set short retention-days on temporary artifacts to avoid accumulation.
Artifact upload succeeds but shows 0 bytes — this happens when the path matches a directory structure but the files inside are empty, or when a previous step’s output was to stderr (and the files weren’t created). Add a run: ls -la <path> step before the upload to confirm files exist and have content.
Windows path separator issues — on Windows runners, use forward slashes in path: values even though Windows uses backslashes. GitHub Actions normalizes paths, but mixing separators can cause matching failures:
# Works on all platforms
path: build/output/ # Use forward slashes
# Avoid
path: build\output\ # May not work on Linux/macOS agentsFor related CI/CD issues, see Fix: GitHub Actions Cache Not Working and Fix: GitHub Actions Timeout.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: GitHub Actions Secret Not Available — Environment Variable Empty in Workflow
How to fix GitHub Actions secrets that appear empty or undefined in workflows — secret scope, fork PR restrictions, environment protection rules, secret names, and OIDC alternatives.
Fix: GitHub Actions Matrix Strategy Not Working — Jobs Not Running or Failing
How to fix GitHub Actions matrix strategy issues — matrix expansion, include/exclude patterns, failing fast, matrix variable access, and dependent jobs with matrix outputs.
Fix: GitHub Actions Docker Build and Push Failing
How to fix GitHub Actions Docker build and push errors — registry authentication, image tagging, layer caching, multi-platform builds, and GHCR vs Docker Hub setup.
Fix: GitHub Actions Environment Variables Not Available Between Steps
How to fix GitHub Actions env vars and outputs not persisting between steps — GITHUB_ENV, GITHUB_OUTPUT, job outputs, and why echo >> $GITHUB_ENV is required.