Docker Pull Access Denied (tested)

This error is misleading: despite the wording, it's almost never about your login or permissions. Docker Hub returns the same generic 'access denied' response whether an image is truly private and you lack access, or the repository name simply doesn't exist — so a typo looks identical to a real permissions problem.

1. Reproduced: a typo'd or nonexistent image name

docker pull alpin
Using default tag: latest
Error response from daemon: pull access denied for alpin,
repository does not exist or may require 'docker login'

Nothing is actually denied here — alpin (missing the final e) simply isn't a real repository. Docker's own message hedges between the two possibilities ("does not exist or may require login") because, from Docker Hub's API response, it genuinely can't distinguish them without you being authenticated.

2. Reproduced: same message for a made-up namespace

docker pull thisrepodoesnotexist12345/nope
Using default tag: latest
Error response from daemon: pull access denied for thisrepodoesnotexist12345/nope,
repository does not exist or may require 'docker login'

Identical wording to the typo case. This is the key thing to understand: this exact error is what you'd also see if the image were real but genuinely private and you weren't logged in as an authorized user. The message alone can't tell you which situation you're in.

3. A different error for a bad tag on a real image

If the repository name is correct but the tag doesn't exist, Docker gives a more specific (and more useful) error instead:

docker pull alpine:this-tag-does-not-exist
Error response from daemon: failed to resolve reference
"docker.io/library/alpine:this-tag-does-not-exist":
docker.io/library/alpine:this-tag-does-not-exist: not found

This one names the image and confirms it exists, just not at that tag — a strong signal the fix is to check the tag list on the registry, not your credentials. (Older Docker versions, and some other registries, phrase this as manifest unknown instead of not found — same cause, different wording, per Docker's release notes.)

4. How to actually tell which case you're in

  1. Check spelling and namespace first. Most "access denied" reports are a typo, a missing library/ for official images used in other contexts, or a missing organization prefix (e.g. myorg/myimage vs just myimage).
  2. Check the registry in a browser (logged out). If the image page loads publicly, it's not a permissions issue — re-check the exact name and tag you typed.
  3. If it's a private image, authenticate and retry.
    docker login
    docker pull yourorg/private-image
    A real permissions failure will look identical to a typo until you've confirmed you're logged in as a user with access — so always do this step before concluding it's a permissions bug in your CI pipeline or Dockerfile.

5. Common real cause: CI pipelines losing login state

Outside of typos, the most frequent real-world trigger is a CI job that pulls a private image in a later step after the docker login session from an earlier step expired or ran in a different container/shell that didn't share credentials. If a pull worked locally but fails identically in CI, check whether the login step actually ran in the same execution context as the pull, not just earlier in the pipeline file.

Frequently asked questions

Does 'pull access denied' always mean a login problem?

No, we confirmed this directly: the identical message appeared both for a simple typo (alpin instead of alpine) and for a completely nonexistent made-up repository name, neither of which has anything to do with permissions.

How do I tell a typo from a real permissions issue?

Check the image on the registry's website while logged out of any account. If the page loads publicly, the problem is the name or tag you typed, not access rights. If the page itself requires login to view, it's genuinely private and you need docker login.

Why did I get a different, more specific error for a bad tag?

We reproduced this too: pulling a real image (alpine) with a nonexistent tag returned 'not found' and explicitly named the image as resolved, unlike the generic access-denied message for a nonexistent repository. The clearer message appears specifically when the repository itself is confirmed valid.

My pull works locally but fails in CI with this error — why?

The most common real cause (not a typo) is that the docker login from an earlier CI step didn't carry over to the step that runs the pull, often because they run in different job containers or shells. Re-authenticate in the same step/context that does the pull.

Is 'manifest unknown' the same thing as this error?

It's related but distinct: manifest unknown (an older wording some registries still use, per their docs) specifically means the repository was found but the tag/digest wasn't, which we reproduced as 'not found' on current Docker. 'Pull access denied' is the separate, more ambiguous message for when the repository name itself can't be resolved at all.

Written with AI assistance. Measured on 2026-10-03 with Docker Engine 29.8.1 on Linux, pulling real (and deliberately nonexistent) public images. Every error message below is copy-pasted output, not paraphrased. PlainHeaders is our extension; Docker is free.