GitLab CI Error Guide: 'manifest unknown' — Fix Missing Image Tag Pulls
Fix 'manifest unknown' in GitLab CI: the image tag or digest doesn't exist in the registry. Correct the tag, wait for the push, fix the registry path, and re-pull.
- #gitlab
- #ci-cd
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
A GitLab CI job fails when it asks a registry for an image tag or digest that the registry cannot find. The runner prints this while preparing the job image or during a docker pull:
ERROR: Job failed: failed to pull image "registry.example.com/team/app:v1.4.2"
with specified policies [always]: manifest unknown: manifest unknown (manager.go:...)
The plain docker pull variant is identical in meaning:
Error response from daemon: manifest for registry.example.com/team/app:v1.4.2 not found: manifest unknown: manifest unknown
Unlike an auth error, the registry accepted your credentials — the reference itself simply doesn’t exist there.
Symptoms
- The job never starts its script; it fails while pulling the
image:or aservices:image. - A
docker pull/docker runstep fails withmanifest unknownfor a tag you expected to exist. - The same repo works for other tags (e.g.,
:latest) but not the specific tag/digest requested. - A downstream job pulls an image a previous job was supposed to push, but the push hasn’t finished or failed.
- Multi-arch pulls fail on one platform because that platform’s manifest wasn’t published.
Common Root Causes
- Tag doesn’t exist — a typo, wrong version, or a tag that was never pushed (or was deleted by a cleanup policy).
- Race between push and pull — a downstream job pulls before the upstream build finished pushing the tag.
- Wrong registry path — the image name points at the wrong project/namespace or an external registry that doesn’t hold it.
- Digest no longer present — pinning
@sha256:...to a digest that expired via retention/garbage collection. - Cleanup policy pruned it — a GitLab Container Registry cleanup policy deleted the tag between build and deploy.
- Multi-arch gap — the tag exists for
amd64but not the requestedarm64(or vice versa); the platform manifest is missing. - Case / normalization — registry paths are case-sensitive;
Appvsappyields a different, non-existent repo.
Diagnostic Workflow
Confirm whether the tag actually exists in the registry before touching the pipeline:
check-tag:
image: quay.io/skopeo/stable:latest
script:
- skopeo login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
- skopeo list-tags docker://$CI_REGISTRY_IMAGE # does the tag appear?
- skopeo inspect docker://$CI_REGISTRY_IMAGE:$WANTED_TAG # errors if manifest unknown
Inspect the manifest and its platforms directly with the registry API or docker buildx:
inspect-manifest:
image: docker:26.1.4
services: [docker:26.1.4-dind]
script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
- docker buildx imagetools inspect $CI_REGISTRY_IMAGE:$WANTED_TAG # lists platforms/digests
For push/pull races, gate the pulling job on the pusher with needs: so it cannot run early:
deploy:
needs: ["build-and-push"] # deploy only after the push job succeeds
script:
- docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
Example Root Cause Analysis
A deploy job intermittently failed with manifest unknown for :$CI_COMMIT_SHORT_SHA. The pipeline built and pushed the image in one job and deployed in another, but both were in the same stage with no dependency:
stages: [ci]
build:
stage: ci
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
deploy:
stage: ci # same stage — could start before build pushed
script:
- docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
Because both jobs shared a stage and ran on parallel runners, deploy sometimes pulled the tag before build finished pushing it — the manifest genuinely didn’t exist yet, so the registry returned manifest unknown. The fix was to order the jobs with an explicit dependency:
stages: [build, deploy]
build:
stage: build
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
deploy:
stage: deploy
needs: ["build"] # cannot pull until the push succeeded
script:
- docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
The team also relaxed an over-aggressive cleanup policy that had been deleting recent SHA tags within minutes, which had caused a second, rarer instance of the same error at deploy time.
Prevention Best Practices
- Use immutable, unique tags (
$CI_COMMIT_SHORT_SHA) and reference the exact tag you pushed; avoid pulling:latestfor deploys. - Order push→pull with
needs:/stages so a consumer never runs before the producer finishes pushing. - Verify a tag exists (
skopeo inspect/docker buildx imagetools inspect) before a deploy relies on it. - Tune Container Registry cleanup policies so they don’t prune tags a deploy still needs; keep a retention window that covers the release cycle.
- For multi-arch, confirm the manifest list includes every platform you pull; publish all platforms in the same push.
- Double-check the full registry path and case;
$CI_REGISTRY_IMAGEis the canonical, correctly-cased project path. - When pinning digests, re-pin after any registry garbage collection that could remove the referenced blob.
Quick Command Reference
# List tags actually present in the registry
skopeo list-tags docker://registry.example.com/team/app
# Inspect a specific tag/digest (errors on manifest unknown)
skopeo inspect docker://registry.example.com/team/app:v1.4.2
# Show platforms in a manifest list (multi-arch gaps)
docker buildx imagetools inspect registry.example.com/team/app:v1.4.2
# Re-tag/push if the tag was missing
docker tag app:local registry.example.com/team/app:v1.4.2
docker push registry.example.com/team/app:v1.4.2
Conclusion
manifest unknown means the registry authenticated you but could not find the requested tag or digest — it was never pushed, was pruned by a cleanup policy, points at the wrong path, is missing for the requested platform, or is being pulled before its push completed. Verify the tag exists with skopeo/imagetools, order producers before consumers with needs:, use immutable SHA tags, and keep retention policies from deleting images a deploy still depends on.
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.