GitLab CI registry "401 Unauthorized" on image pull in CI
The registry returned 401 when the runner tried to pull an image: the credentials are missing, expired, or wrong. Unlike "pull access denied" for nonexistent repos, a 401 means authentication itself failed.
What this error means
Image pull fails with "unauthorized: HTTP status: 401 Unauthorized" or "Error response from daemon: Get ...: unauthorized".
Error response from daemon: Get "https://registry.example.com/v2/app/manifests/latest": unauthorized: HTTP Basic: Access denied. HTTP status: 401 UnauthorizedCommon causes
Expired or wrong registry credentials
A stale token, rotated password, or wrong username in DOCKER_AUTH_CONFIG causes the registry to reject the pull with 401.
Using a job token outside its scope
The $CI_JOB_TOKEN only authenticates to registries it is allowed to access; using it elsewhere returns 401.
How to fix it
Refresh the registry credentials
- Regenerate the token or deploy credentials for the registry.
- Update the masked
DOCKER_AUTH_CONFIGvariable. - Re-run the job.
# log in to the GitLab registry inside the job
docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"Use credentials valid for that registry
For an external registry, provide a token with pull scope rather than the job token, which is scoped to GitLab.
How to prevent it
- Rotate registry tokens before they expire and update the secret in one place.
- Use
$CI_REGISTRY_*variables for the GitLab registry. - Scope tokens to the registries they need to access.