The upload-artifact GitHub Actions workflow step is failing because the specified file or directory path doesn’t exist on the runner at the time the action runs.

Here’s what’s actually breaking: The actions/upload-artifact action is a separate process from your main job’s code execution. When it’s time for upload-artifact to run, it looks for the files you told it to upload at the path you provided. If that path is empty or points to something that was deleted or never created by a previous step, upload-artifact can’t find anything to upload and throws this error. It’s like asking someone to mail a package, but you haven’t put anything in the box before handing it to them.

Common Causes and Fixes:

  1. Artifact Path Typo or Incorrect Name:

    • Diagnosis: Double-check the path parameter in your upload-artifact step against the actual directory or file name created in a previous step. Case sensitivity matters!
    • Fix: Correct the path value. For example, if a previous step created a directory named build-output, your upload-artifact step should look like:
      - name: Upload build output
        uses: actions/upload-artifact@v3
        with:
          name: my-build-artifacts
          path: build-output
      
    • Why it works: Ensures the action is looking for the artifact at the precisely correct location.
  2. Artifact Not Created in Time (Race Condition):

    • Diagnosis: If the artifact is generated by a preceding step, ensure that step has completed successfully and actually created the files before the upload-artifact step begins. Sometimes, asynchronous operations or complex build processes can lead to the artifact directory being empty when upload-artifact checks.
    • Fix: Ensure the upload-artifact step has needs set to the step that generates the artifact, or that it’s part of the same job and runs sequentially after the generation step. If the generation is complex, consider adding a simple ls or echo command in a step right before upload-artifact to print the contents of the expected directory to the logs for verification.
      - name: Verify artifact directory contents
        run: |
          echo "Contents of ./build-output:"
          ls -la ./build-output
      
    • Why it works: Explicitly confirms the artifact exists and is accessible before attempting to upload it, and ensures the upload step waits for generation.
  3. Incorrect Working Directory:

    • Diagnosis: The path is relative to the runner’s current working directory. If your build process or subsequent steps change the working directory (working-directory in a step or cd commands in a script), the path might be looking in the wrong place.
    • Fix: Either specify an absolute path (less common and less portable) or ensure the path is relative to the expected working directory of the upload-artifact step. You can explicitly set the working-directory for the upload-artifact step if needed, or ensure your previous steps don’t change it unexpectedly.
      - name: Build and Archive
        run: |
          mkdir my-app-files
          echo "some content" > my-app-files/config.txt
        working-directory: ./src # Example: build happens in ./src
      
      - name: Upload artifact
        uses: actions/upload-artifact@v3
        with:
          name: config-files
          path: ./src/my-app-files # Path relative to repo root
      
    • Why it works: Aligns the path lookup with where the files are actually located on the runner’s filesystem.
  4. Artifact Path is a File, Not a Directory (or vice-versa):

    • Diagnosis: The upload-artifact action can upload both files and directories. However, if you specify a path that looks like a directory but is actually a file, or vice-versa, it might behave unexpectedly depending on the action’s internal logic and the exact version. More critically, if the path you specify should be a directory but contains no files, it will also fail.
    • Fix: Ensure the path correctly points to the intended entity. If you intend to upload a single file named results.json, the path should be results.json. If you intend to upload everything in a directory called output, the path should be output. If output is empty, you’ll still get an error. Add a check to ensure files are present.
      - name: Generate report
        run: |
          echo "Report content" > my_report.txt
      
      - name: Check if report exists
        run: |
          if [ ! -f "my_report.txt" ]; then
            echo "Error: my_report.txt not found!"
            exit 1
          fi
      
      - name: Upload report
        uses: actions/upload-artifact@v3
        with:
          name: report
          path: my_report.txt
      
    • Why it works: Verifies the existence and type of the artifact before attempting to upload, and clarifies whether you’re uploading a file or its containing directory.
  5. Conditional Logic Skipping Artifact Creation:

    • Diagnosis: If the step that creates the artifact is skipped due to if conditions (e.g., if: github.ref == 'refs/heads/main'), but the upload-artifact step is not also guarded by the same condition, upload-artifact will run and find nothing.
    • Fix: Ensure that any if conditions that prevent artifact creation also prevent the upload-artifact step from running.
      jobs:
        build:
          runs-on: ubuntu-latest
          if: github.ref == 'refs/heads/main' # Job only runs on main branch
          steps:
            - name: Checkout code
              uses: actions/checkout@v3
      
            - name: Build
              run: echo "Building..." # This step runs because the job condition passes
      
            - name: Upload artifact
              uses: actions/upload-artifact@v3
              with:
                name: build-output
                path: ./build # This path is created by the 'Build' step
      
    • Why it works: Prevents the upload action from executing when the artifact it’s supposed to upload hasn’t been generated.
  6. Runner Environment Differences:

    • Diagnosis: While less common, if your build process relies on specific tools or configurations that are present on your local machine but missing from the GitHub Actions runner, the artifact might not be created as expected.
    • Fix: Ensure your workflow runs-on a runner type that has all necessary dependencies installed. You might need to use actions/setup-node, actions/setup-python, etc., or install tools manually within your run steps.
      jobs:
        build:
          runs-on: ubuntu-latest
          steps:
            - name: Checkout code
              uses: actions/checkout@v3
      
            - name: Set up Node.js
              uses: actions/setup-node@v3
              with:
                node-version: '18'
      
            - name: Build with Node
              run: npm ci && npm run build # This creates the 'dist' directory
      
            - name: Upload build artifacts
              uses: actions/upload-artifact@v3
              with:
                name: web-app
                path: dist # Assuming your build output is in 'dist'
      
    • Why it works: Guarantees the environment has the necessary software to successfully execute the build steps that create the artifact.

The next error you’ll likely see if you fix this is a "Permissions denied" error when trying to upload if the artifact path is a directory but contains files that the runner doesn’t have read access to, or a general "Upload failed" with a more obscure HTTP error code if the artifact itself is somehow corrupted or too large for the configured limits.

Want structured learning?

Take the full Github-actions course →