Skip to content
Latchkey

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".

GitLab Runner
Error response from daemon: Get "https://registry.example.com/v2/app/manifests/latest": unauthorized: HTTP Basic: Access denied. HTTP status: 401 Unauthorized

Common 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

  1. Regenerate the token or deploy credentials for the registry.
  2. Update the masked DOCKER_AUTH_CONFIG variable.
  3. Re-run the job.
bash
# 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.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →