What's Actually Happening

GitHub Actions workflow cannot find artifacts. Download fails because artifact doesn't exist or is not accessible.

The Error You'll See

```yaml - uses: actions/download-artifact@v4

Error: Unable to find artifact named 'my-artifact' ```

Artifact expired:

bash
Error: Artifact has expired

Permission denied:

bash
Error: Not authorized to access artifact

No artifacts:

```yaml - uses: actions/download-artifact@v4

Error: No artifacts found for download ```

Why This Happens

  1. 1.Upload failed - Artifact not uploaded successfully
  2. 2.Wrong name - Artifact name mismatch
  3. 3.Different workflow - Artifact from different workflow run
  4. 4.Expired - Artifact retention period passed
  5. 5.Permissions - Insufficient permissions to access
  6. 6.No artifacts created - Job didn't create artifacts

Step 1: Check Artifact Upload

```yaml # Verify upload step in workflow:

  • name: Upload Artifact
  • uses: actions/upload-artifact@v4
  • with:
  • name: my-artifact
  • path: dist/
  • retention-days: 5

# Check job output: # In GitHub UI -> Actions -> Run -> Job -> Upload step # Should show: "Artifact my-artifact successfully uploaded"

# Verify upload path exists: - name: Check files run: | ls -la dist/

  • name: Upload Artifact
  • uses: actions/upload-artifact@v4
  • with:
  • name: my-artifact
  • path: dist/

# Use if-no-files-found: - uses: actions/upload-artifact@v4 with: name: my-artifact path: dist/ if-no-files-found: error # or warn, ignore ```

Step 2: Check Artifact Name

```yaml # Upload artifact: - uses: actions/upload-artifact@v4 with: name: my-artifact # This name path: dist/

# Download artifact - must match: - uses: actions/download-artifact@v4 with: name: my-artifact # Must match exactly

# Case-sensitive! # my-artifact != My-Artifact

# Download all artifacts: - uses: actions/download-artifact@v4

# Download specific artifact: - uses: actions/download-artifact@v4 with: name: my-artifact

# Pattern matching: - uses: actions/download-artifact@v4 with: pattern: my-artifact-* path: artifacts/ ```

Step 3: Check Job Dependencies

```yaml # Jobs run in parallel by default # Download job must wait for upload job:

jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm build - uses: actions/upload-artifact@v4 with: name: my-artifact path: dist/

deploy: needs: build # Wait for build job runs-on: ubuntu-latest steps: - uses: actions/download-artifact@v4 with: name: my-artifact

# If needs missing, deploy runs before build completes ```

Step 4: Check Artifact Retention

```yaml # Default retention is 90 days # Shorter retention may expire:

  • uses: actions/upload-artifact@v4
  • with:
  • name: my-artifact
  • path: dist/
  • retention-days: 1 # Only 1 day!

# Check retention in UI: # Actions -> Artifacts -> my-artifact # Shows expiration date

# Increase retention: - uses: actions/upload-artifact@v4 with: name: my-artifact path: dist/ retention-days: 30

# Repository settings also affect retention: # Settings -> Actions -> General -> Artifact and log retention ```

Step 5: Fix Cross-Workflow Access

```yaml # To download artifact from different workflow:

jobs: download: runs-on: ubuntu-latest steps: - name: Download artifact from another workflow uses: actions/download-artifact@v4 with: name: my-artifact github-token: ${{ secrets.GITHUB_TOKEN }} run-id: ${{ github.event.workflow_run.id }}

# Or use dawidd6/action-download-artifact: - uses: dawidd6/action-download-artifact@v3 with: workflow: build.yml name: my-artifact path: dist/ github_token: ${{ secrets.GITHUB_TOKEN }}

# For specific workflow run: - uses: dawidd6/action-download-artifact@v3 with: workflow: build.yml run_id: 1234567890 name: my-artifact ```

Step 6: Check Permissions

```yaml # Ensure proper permissions:

jobs: build: runs-on: ubuntu-latest permissions: contents: read actions: write # Needed to upload artifacts steps: - uses: actions/upload-artifact@v4

download: runs-on: ubuntu-latest permissions: contents: read actions: read # Needed to download artifacts steps: - uses: actions/download-artifact@v4

# At workflow level: permissions: contents: read actions: write

# For cross-repo access: - uses: actions/download-artifact@v4 with: name: my-artifact github-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} repository: owner/repo run-id: 1234567890 ```

Step 7: Debug Artifact Issues

```yaml # List all artifacts in job:

  • name: List artifacts
  • env:
  • GH_TOKEN: ${{ github.token }}
  • run: |
  • gh api repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts

# Check artifact existence: - name: Check artifact run: | gh api repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts \ --jq '.artifacts[] | select(.name == "my-artifact")'

# Debug download: - name: Download with debug uses: actions/download-artifact@v4 with: name: my-artifact continue-on-error: true

  • name: List downloaded
  • run: ls -la

# Check workflow run: - name: Get workflow run info run: | gh run view ${{ github.run_id }} --json artifacts ```

Step 8: Handle Matrix Builds

```yaml # Matrix build creates multiple artifacts:

jobs: build: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/upload-artifact@v4 with: name: artifact-${{ matrix.os }} path: dist/

# Download all matrix artifacts: - uses: actions/download-artifact@v4 with: pattern: artifact-* path: artifacts/ merge-multiple: true

# Or specific matrix artifact: - uses: actions/download-artifact@v4 with: name: artifact-ubuntu-latest ```

Step 9: Fix v4 Breaking Changes

```yaml # actions/upload-artifact@v4 and download-artifact@v4 changes:

# v3 behavior (implicit merge): - uses: actions/download-artifact@v3 # Downloads all artifacts to current directory

# v4 behavior (explicit): - uses: actions/download-artifact@v4 # Error if name not specified! with: name: my-artifact

# Download all in v4: - uses: actions/download-artifact@v4 # No name specified = download all

# Path changes in v4: - uses: actions/download-artifact@v4 with: name: my-artifact path: my-artifact/ # Creates directory # Files: my-artifact/file1, my-artifact/file2

# Merge multiple artifacts: - uses: actions/download-artifact@v4 with: pattern: artifact-* merge-multiple: true path: merged/ ```

Step 10: GitHub Actions Artifact Verification

```yaml # Add verification step to workflow:

  • name: Verify Artifact
  • if: always()
  • run: |
  • echo "=== Checking artifact upload ==="

# List all artifacts gh api repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts \ --jq '.artifacts[] | "Name: \(.name), ID: \(.id), Size: \(.size_in_bytes)"'

echo "" echo "=== Checking artifact files ===" if [ -d "my-artifact" ]; then echo "Artifact directory exists" ls -la my-artifact/ else echo "ERROR: Artifact directory not found" fi env: GH_TOKEN: ${{ github.token }}

# Or create composite action: # .github/actions/check-artifact/action.yml name: 'Check Artifact' inputs: artifact-name: required: true runs: using: 'composite' steps: - shell: bash run: | gh api repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts \ --jq '.artifacts[] | select(.name == "${{ inputs.artifact-name }}")' ```

GitHub Actions Artifact Checklist

CheckExpected
Upload succeeded"successfully uploaded"
Name matchesSame name upload/download
Job dependsneeds: upload-job
RetentionNot expired
Permissionsactions: read/write
Path existsFiles uploaded

Verify the Fix

```yaml # After fixing artifact issue

# 1. Check upload in workflow logs // Artifact uploaded successfully

# 2. Verify in UI # Actions -> Run -> Artifacts // Artifact listed

# 3. Download succeeds - uses: actions/download-artifact@v4 with: name: my-artifact // Files downloaded

# 4. Check file contents - run: ls -la my-artifact/ // Expected files present

# 5. Use in downstream job // Job succeeds with artifact

# 6. Test retention # Wait specified days // Artifact still available ```

  • [Fix GitHub Actions Workflow Failed](/articles/fix-github-actions-workflow-failed)
  • [Fix GitLab CI Pipeline Stuck](/articles/fix-gitlab-ci-pipeline-stuck)
  • [Fix Jenkins Build Stuck](/articles/fix-jenkins-build-stuck)