# GitHub Actions Unable to resolve action, and which half failed

> GitHub Actions Unable to resolve action arrives in two forms, and each tells you how far the lookup got before it stopped. Learn to read both.

Source: https://latchkey.dev/learn/github-actions/gha-uses-action-not-found  
Updated: 2026-09-20

GitHub Actions Unable to resolve action appears in two forms, and the difference between them is the whole diagnosis: one says the repository could not be found, and the other says the repository was found but the ref you asked for was not. Nothing downloads and no action code runs in either case, because the reference is resolved before anything is fetched.

## What this error means

A step fails at the very start with a single line and no other output. There is no setup log for the action, no inputs echoed, nothing from the action itself, because the action was never obtained. The step that fails is often one nobody touched, in a workflow that has been green for months, which makes a repository rename or a deleted tag the first thing to suspect rather than the workflow file.

```Quoted from gigalixir/gigalixir-action#67, reported verbatim by the user
Error: Unable to resolve action `gigalixir/gigalixir-action@v1`, unable to find version `v1`
```

## Common causes

### The tag or branch in the reference does not exist

Usually a major version tag the maintainer has not published, or a tag that was deleted or renamed during a release. The message names the version, which is the fastest confirmation available, and listing the repository's tags settles it in one command.

### The repository was renamed or moved

A `uses` reference to the old owner or name can stop resolving even though the browser redirect still works, so a workflow that nobody edited fails on a step that used to pass. This is the version that produces the most confusing bug reports.

### The action is private and not shared with the calling repository

A private action has to allow access from other repositories in the organization. Without that, resolution fails with the repository not found ending, which sends people to check a path that was never wrong.

### The path is misspelled or wrongly cased

Less common than the others and worth ruling out first because it costs nothing. In our experience the case version appears when a reference is retyped from a README rendered with different capitalization.

## How to fix it

### List the refs on the action repository

Ask the repository what it actually publishes before changing anything. If the tag you referenced is not in the list, the reference is the problem; if it is, you are looking at an access or naming question instead.

```Terminal
gh api repos/OWNER/ACTION/git/matching-refs/tags --jq '.[].ref' | tail -20
```

### Pin to a commit SHA for anything that matters

A commit SHA cannot be moved or deleted by the action's maintainer, which removes this whole failure mode for that step. The documentation recommends it as the safest reference for stability and security, and a dependency updater can still raise pull requests to advance it.

```.github/workflows/ci.yml (illustrative)
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
```

### Allow a private action to be used by other repositories

1. Open the settings of the repository that holds the action, not the one running the workflow.
2. In the Access section, select the option making it accessible from repositories in the organization.
3. Re-run the failing job and confirm the ending of the message changes or disappears.
4. If the action is only ever used by one repository, consider moving it into that repository instead.

### Reference a local action by path when it is internal

Checking the action out and calling it with a relative path avoids the action lookup entirely, because the reference resolves against the workspace. This is the right shape for an action that has no reason to be discoverable outside the repository.

```.github/workflows/ci.yml (illustrative)
- uses: actions/checkout@v7
- uses: ./.github/actions/build
```

## How to prevent it

- Verify that a referenced tag exists at the moment you add the reference.
- Pin actions you depend on to commit SHAs and let an updater advance them.
- Update `uses` paths in the same change that renames a repository.
- Set access on the action's repository when you first publish an internal action.

## Read the ending of the line, not the beginning

Both forms open the same way, so the informative part is what comes after the reference. An ending of "repository not found" means the owner and repository part of your `uses` value did not resolve to something the run is allowed to see. An ending of "unable to find version" means it did resolve, and the tag, branch or commit after the @ did not exist there.

That split maps to two different searches. For the first, whose reported form is `Error: Unable to resolve action. Repository not found: ytanikin/PRConventionalCommits`, check the spelling and case of the path, check whether the repository was renamed or made private, and check whether this run has access to it at all. For the second, the repository is fine and you are looking at a tag question: a major version tag that was never published, a tag that was deleted or moved, or a branch that was renamed.

Resolution happens before any download, which is why neither form leaves a partial log. The runner collects the references a job needs and asks the service to resolve them, and a failure there means the job stops with one line rather than with a half-downloaded action.

| How the line ends | How far the lookup got | What to check first |
| --- | --- | --- |
| `repository not found` | the owner and repository never resolved | spelling, a rename, a private repository, org policy |
| `unable to find version `x`` | the repository resolved, the ref did not | whether the tag or branch exists on that repository |
| names a repository you renamed | the redirect was not followed | update the `uses` path to the current name |
| names your own private action | the run has no access to it | repository settings for Actions access |

> Renames are the version of this that looks least like a mistake. GitHub redirects browser and clone traffic for a renamed repository, and a `uses` reference to the old name can still fail to resolve, which is why a workflow that has not changed starts failing on a step nobody edited.

## Why a major version tag can vanish

The convention that `uses: owner/action@v3` keeps working is a convention, not a guarantee. It relies on the action's maintainer publishing and moving a lightweight `v3` tag alongside each `v3.x.y` release, and the documentation says as much: it notes that the behavior of major version tags is at the discretion of the action's author.

So a README instructing you to use `@v3` can be ahead of the tags, behind them, or simply wrong, and the failure you get names the version rather than the README. Two public reports quoted in this hub are exactly that: a README saying `@v1` for an action whose `v1` tag had not been published, and another saying `@v3` for the same reason.

The response is not to avoid major tags, which are genuinely useful, but to verify the ref exists when you first add it and to know that a pin to a commit SHA is the only reference that cannot be moved out from under you. The documentation recommends the SHA for stability and security for that reason.

```Terminal
gh api repos/OWNER/ACTION/git/matching-refs/tags/v --jq '.[].ref'
```

## Private actions, and the access that is not the token

When the action lives in a private repository in your own organization, the failing form is usually repository not found, which reads as though the path is wrong. The path is fine. What is missing is that the repository holding the action has not allowed its workflows and actions to be used by other repositories in the organization, which is a setting on the action's repository rather than on the workflow's.

This one is worth stating plainly because the instinct is to reach for a token. A personal access token with repository access does not change the answer, because the resolution is not a clone you are authenticating: it is the service deciding whether this run may use that action. The fix is a setting.

The alternative, which avoids the question entirely, is to check the action out into the workspace and call it by a relative path. A local `uses: ./path` reference resolves against the checked out repository rather than through the action lookup, and it is the pattern to reach for when an action is genuinely internal.

## Why there is no recorded run on this page

Both forms of the message are produced when the run resolves its action references, which happens before the action is downloaded and therefore before there is anything for a runner to log beyond the one line. A Latchkey recording would consist of that line and nothing else.

More to the point, producing one means writing a workflow that references a repository or a tag that does not exist, which is manufacturing the evidence rather than observing it. Both forms are quoted here from public reports where real repositories and real missing tags produced them, which is a stronger provenance than a failure we would have staged.

## FAQ

### What is the difference between repository not found and unable to find version?

How far the lookup got. Repository not found means the owner and repository part of your `uses` value never resolved, so spelling, renames, privacy and policy are in scope. Unable to find version means the repository resolved and the tag, branch or commit after the @ does not exist there.

### Why did an action start failing when I did not change the workflow?

Most often because something changed on the other end: a major version tag was deleted or moved during a release, a branch was renamed, or the repository itself was renamed or made private. The reference in your file is static, and everything it points at belongs to somebody else.

### Does a personal access token fix a private action that cannot be resolved?

No. Resolving an action reference is not a clone you authenticate, it is the service deciding whether this run may use that action. The setting lives on the repository that holds the action, allowing its actions and workflows to be used by other repositories in the organization.

### Should I pin actions to a commit SHA?

For anything you depend on, yes. A SHA cannot be moved or deleted by the maintainer, which removes this failure entirely for that step, and the documentation recommends it as the safest reference. Keep a comment naming the version so the pin stays readable, and let a dependency updater advance it.

## References

- [GitHub Actions: workflow syntax, jobs.<job_id>.steps[*].uses](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax)
- [gigalixir/gigalixir-action#67, the unable to find version form](https://github.com/gigalixir/gigalixir-action/issues/67)
- [ytanikin/pr-conventional-commits#29, the repository not found form](https://github.com/ytanikin/pr-conventional-commits/issues/29)
- [GitHub Actions: share actions and workflows with your organization](https://docs.github.com/en/actions/how-tos/reuse-automations/share-with-your-organization)

---

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
