# No artifacts named github-pages were found for this workflow run

> No artifacts named github-pages were found means deploy-pages searched this run only. The outage line printed underneath it is not your problem.

Source: https://latchkey.dev/learn/github-actions/gha-deploy-pages-artifact-not-found  
Updated: 2026-09-20

No artifacts named github-pages were found for this workflow run is `actions/deploy-pages` reporting that its search of the current run came back empty. The search is scoped to that run and cannot be pointed anywhere else, so the fix is always in the job graph or in the artifact name.

## What this error means

The deploy job fails on its only real step, and the log carries two messages rather than one. The first, written as an error, asks whether githubstatus.com is reporting issues with API requests, Pages or Actions, and suggests re-running the deployment later. The second names the artifact and says it was not found. Read in the order they appear, the log invites you to retry an outage. There is no outage. The suggestion is printed by a catch block that wraps every failure of that lookup, including the ordinary case where nothing was ever uploaded, and retrying will produce it again unchanged.

```Reconstructed from getArtifactMetadata in actions/deploy-pages src/internal/api-client.js (v5.0.1). Not captured from a run
Fetching artifact metadata for "github-pages" in this workflow run
Error: No artifacts named "github-pages" were found for this workflow run. Ensure artifacts are uploaded with actions/upload-artifact@v4 or later.
```

## Common causes

### The build job did not upload in this run

The single largest cause, and it covers several shapes: the build job was skipped by a condition, it failed before the upload step, or it is not in this workflow at all. The lookup does not care which; it reports an empty list the same way for all of them.

### The deploy is in a second run triggered by the first

A `workflow_run` chain is a reasonable pattern for ordinary artifacts and does not work here. The action has no token or run-id input and its lookup is scoped to the run it is executing in, so a deploy in a follow-on run can never see what the build run uploaded.

### The names on the two sides disagree

Both the upload and the deploy default to `github-pages`, so they agree until somebody changes one. Setting `name` on `actions/upload-pages-artifact` without setting `artifact_name` on `actions/deploy-pages` leaves a green upload and a red deploy, in two different jobs.

### A generic upload was used instead of the Pages one

Uploading the site directory with `actions/upload-artifact` produces an artifact with the right name and the wrong contents, a zip of loose files rather than the single tar the deployment expects. That usually fails later than this message, but a mismatched name in the same change lands here first.

## How to fix it

### Read the second line, not the first

1. Open the failed deploy job and expand the step.
2. Ignore the sentence about githubstatus.com; it is printed for every failure of this lookup.
3. Read the line that names the artifact, and note the name in the quotes.
4. Open the build job in the same run and confirm an upload step ran and used that name.

### Put both jobs in one workflow, with needs

This is the shape the action is designed for and the one GitHub ships in its own starter workflow. Build and upload in one job, deploy in a second with `needs:` on the first, both in the same file so they are always in the same run.

```.github/workflows/pages.yml (illustrative)
name: pages
on:
  push:
    branches: [main]

permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - run: npm ci && npm run build
      - uses: actions/upload-pages-artifact@v5
        with:
          path: ./dist

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - id: deployment
        uses: actions/deploy-pages@v5
```

### Match the names or delete them both

If you renamed the artifact, set the matching input on the deploy. If you cannot remember why it was renamed, take both settings out and let the defaults agree with each other, which is what they were chosen to do.

```.github/workflows/pages.yml (illustrative)
- uses: actions/upload-pages-artifact@v5
        with:
          path: ./dist
          name: docs-site

      - id: deployment
        uses: actions/deploy-pages@v5
        with:
          artifact_name: docs-site
```

### Check the run rather than the repository

When you are unsure whether the upload happened where it needed to, list the artifacts of that specific run. An empty list confirms the diagnosis immediately and costs one command, and it distinguishes a naming problem from an upload that never happened.

```Terminal
gh api "repos/OWNER/REPO/actions/runs/RUN_ID/artifacts" \
  --jq '.total_count, (.artifacts[] | .name)'
```

## How to prevent it

- Keep the Pages build and the Pages deploy in one workflow file.
- Leave `name` and `artifact_name` at their defaults unless a run deploys two sites.
- Never put the Pages upload step inside a matrix.
- Treat the githubstatus sentence in this step as noise, not as a diagnosis.

## The lookup, and the sentence wrapped around it

This is the function that produces both lines. The artifact client is called with no options at all, which means it uses the run-scoped internal path and resolves the backend identifiers from the runtime token the runner holds. There is no parameter here for another run and no input on the action that would supply one.

The outer catch is the part that misleads. It runs for every failure inside the block, so the ordinary empty-list case gets the same outage sentence as a genuine service problem. The error you want is the inner one, which names the artifact.

```actions/deploy-pages, src/internal/api-client.js (v5.0.1)
const filteredArtifacts = response.data.artifacts.filter(artifact => artifact.name === artifactName)

if (artifactCount === 0) {
  throw new Error(
    `No artifacts named "${artifactName}" were found for this workflow run. Ensure artifacts are uploaded with actions/upload-artifact@v4 or later.`
  )
}
...
} catch (error) {
  core.error(
    'Fetching artifact metadata failed. Is githubstatus.com reporting issues with API requests, Pages, or Actions? Please re-run the deployment at a later time.',
    error
  )
  throw error
}
```

## Three ways the artifact is not there

The scope of the lookup is the whole diagnosis. Artifacts belong to a run, jobs within a run share them, and jobs in a different run do not. So the question to answer first is not whether the upload succeeded but whether it succeeded in this run.

That rules the `workflow_run` pattern out entirely for Pages. Building in one workflow and deploying from a second, triggered by the first, is a perfectly reasonable shape for ordinary artifacts, which can be fetched across runs with a token. `actions/deploy-pages` has no such input, so the second run sees an empty list no matter what the first one uploaded.

| What the log says | Where the artifact is | What to change |
| --- | --- | --- |
| No artifacts named github-pages | nowhere; the upload never ran | fix or unskip the build job |
| No artifacts named github-pages | in the run, under another name | match `artifact_name` to the upload `name` |
| No artifacts named github-pages | in a different run | move the deploy into the run that builds |
| Multiple artifacts named github-pages | in the run, twice | stop a matrix leg from uploading twice |

## The ordering rule that is easy to get half right

A deploy job needs `needs:` pointing at the build job, and that is necessary rather than sufficient. `needs:` orders the jobs; it does not carry anything between them. What makes the artifact visible is that both jobs are in the same run, which they are by construction once they are in the same workflow file.

The failure people hit with `needs:` in place is the skipped upstream. If the build job is skipped by a condition, or fails while the deploy job carries a condition that lets it start anyway, the deploy runs against a run where the upload never happened. The log then looks exactly like the missing-name case, because the lookup cannot distinguish an artifact that was never created from one that was created under a different name.

The last row of the table is rarer and worth a word. If the lookup finds more than one artifact with the name, the action refuses rather than choosing, with a message that counts them. A matrix that includes an upload step with a fixed name is the usual cause, and the fix is to leave the Pages upload outside the matrix entirely.

> If your deploy gets past this step and then fails on a ref or an environment rule, the page for that is [actions/deploy-pages deployment failed](/learn/github-actions/deploy-pages-deployment-failed-environment).

## Why there is no recorded run on this page

Producing this one on purpose means a repository with Pages already enabled and a job graph broken in a specific way, and the thing that would settle it is not in the log. The deciding fact is what the run actually holds, and the action never prints that: the lookup filters the list down to your artifact name and reports only that the result was empty. A recorded run would add a second copy of the two lines already quoted above from the source that writes them, against an artifact list nobody can compare with their own.

It is also not repairable in the moment. The lookup is a single list call over a run whose uploads are already finished, so a retry at any point in the deploy job reads the same empty list. The outage sentence in the log is an invitation to retry, and following it is the most common way to lose an hour to this error.

## FAQ

### Can actions/deploy-pages use an artifact from another workflow run?

No. Its lookup calls the artifact client with no find options, so it resolves the current run from the runtime token and lists only that run. There is no token or run-id input that would change it, which rules out a `workflow_run` chain for Pages deployments.

### Why does deploy-pages mention githubstatus.com when nothing is down?

Because that sentence is written by the catch block wrapping the whole lookup, so it fires for an empty artifact list as readily as for a real outage. It is printed before the specific error and is almost always a distraction. Read the line that names the artifact instead.

### Does needs: make the artifact visible to the deploy job?

Not by itself. Artifacts are visible to every job in the same run, and `needs:` only orders them. What `needs:` prevents is the deploy starting before the upload finished. If the build job is skipped, the ordering holds and the artifact still does not exist.

### What if deploy-pages says multiple artifacts were found?

That is the opposite failure, and the action refuses rather than choosing. It happens when more than one job uploaded under the same name, usually because a Pages upload step ended up inside a matrix. Move the upload out of the matrix so exactly one job produces it.

## References

- [actions/deploy-pages src/internal/api-client.js: getArtifactMetadata and the catch around it](https://github.com/actions/deploy-pages/blob/main/src/internal/api-client.js)
- [actions/deploy-pages action.yml: the artifact_name input and its default](https://github.com/actions/deploy-pages/blob/main/action.yml)
- [GitHub Pages: publishing with a custom GitHub Actions workflow](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site)
- [Storing and sharing data from a workflow: artifacts are scoped to a run](https://docs.github.com/en/actions/how-tos/manage-workflow-runs/download-workflow-artifacts)

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
