Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Kubernetes & Helm By James Joyner IV · · 9 min read

Kubernetes Error Guide: 'manifest unknown' Image Tag or Digest Not in Registry

Fix 'manifest unknown' in Kubernetes: the image tag or digest your pod references does not exist in the registry — find the missing tag and repoint it.

  • #kubernetes-helm
  • #troubleshooting
  • #errors
  • #registry

Exact Error Message

When the kubelet asks a registry for an image tag or digest that the registry does not have, the pull fails and the pod surfaces a manifest unknown error inside an ErrImagePull/ImagePullBackOff loop:

Events:
  Type     Reason     Age                From     Message
  ----     ------     ----               ----     -------
  Normal   Pulling    18s (x3 over 51s)  kubelet  Pulling image "ghcr.io/acme/api:v1.9.3"
  Warning  Failed     17s (x3 over 50s)  kubelet  Failed to pull image "ghcr.io/acme/api:v1.9.3": rpc error: code = NotFound desc = failed to pull and unpack image "ghcr.io/acme/api:v1.9.3": failed to resolve reference "ghcr.io/acme/api:v1.9.3": ghcr.io/acme/api:v1.9.3: not found
  Warning  Failed     17s (x3 over 50s)  kubelet  Error: ErrImagePull
  Normal   BackOff    4s  (x5 over 49s)  kubelet  Back-off pulling image "ghcr.io/acme/api:v1.9.3"

Pulling the same reference directly with the Docker or containerd CLI returns the canonical wording:

Error response from daemon: manifest unknown

The key signal is not found / manifest unknown: the registry, repository, and your credentials are all fine — the specific tag or digest simply is not there.

What the Error Means

A container image reference has three parts: a registry host, a repository path, and a tag or digest (registry/repo:tag or registry/repo@sha256:...). When the kubelet pulls, the registry first resolves the tag or digest to a manifest — the JSON document that lists the image’s layers and config. manifest unknown means the registry successfully received your request and authorized it, but has no manifest matching that exact tag or digest.

This is fundamentally different from authentication or repository-existence failures. A pull access denied or repository does not exist error means the registry rejected you before resolving the tag. manifest unknown means you got far enough that the registry looked up the tag and came back empty. In practice the repository exists and you can read it — the version you named was never pushed, was deleted, or was overwritten.

Common Causes

  • Typo or wrong tagv1.9.3 was requested but the registry only has v1.9.2 and 1.9.3 (no v prefix).
  • Tag never pushed — CI built and tagged the image but the push step failed or was skipped, so the tag does not exist remotely.
  • Tag deleted or expired — a registry retention/garbage-collection policy pruned older tags, or someone deleted the tag.
  • Digest no longer present — a pinned @sha256: digest was garbage-collected after the tag moved to a new build.
  • Wrong architecture in a single-arch image — a multi-arch manifest list is missing the node’s platform (e.g. arm64), so resolution for that platform returns nothing.
  • Wrong repository pathacme/api vs acme/api-service; the path resolves to a real repo but not the one holding your tag.
  • Mutable latest racelatest was retagged to a new digest and the old one pruned mid-rollout.

How to Reproduce the Error

Reference a tag that does not exist in a public repository:

apiVersion: v1
kind: Pod
metadata:
  name: manifest-unknown-demo
spec:
  containers:
    - name: app
      image: registry.k8s.io/pause:does-not-exist
kubectl apply -f manifest-unknown-demo.yaml
kubectl get pod manifest-unknown-demo
NAME                    READY   STATUS         RESTARTS   AGE
manifest-unknown-demo   0/1     ErrImagePull   0          12s

kubectl describe pod manifest-unknown-demo shows the manifest unknown / not found message because the pause repository exists but the does-not-exist tag does not.

Diagnostic Commands

# Read the exact pull error and the image reference the pod uses
kubectl describe pod <POD> | grep -A8 Events
kubectl get pod <POD> -o jsonpath='{.spec.containers[*].image}{"\n"}'

# List the tags that actually exist in the repository (no pull, read-only)
crane ls ghcr.io/acme/api
skopeo list-tags docker://ghcr.io/acme/api

# Inspect a specific tag's manifest without pulling layers
crane manifest ghcr.io/acme/api:v1.9.3
skopeo inspect --raw docker://ghcr.io/acme/api:v1.9.3

# Check which platforms a multi-arch tag publishes
crane manifest ghcr.io/acme/api:v1.9.3 | jq '.manifests[].platform'

# Confirm the node architecture the tag must cover
kubectl get node <NODE> -o jsonpath='{.status.nodeInfo.architecture}{"\n"}'

crane ls (or skopeo list-tags) is the decisive check: if your tag is absent from that list, the manifest genuinely does not exist.

Step-by-Step Resolution

1. Read the exact reference. Copy the full registry/repo:tag string from the describe output. Watch for a missing or extra v prefix and subtle path differences.

2. List the real tags. Run crane ls <repo> or skopeo list-tags docker://<repo>. Confirm whether your tag is present at all.

3. If the tag is missing, repoint to one that exists. Update the deployment to a known-good tag:

kubectl set image deployment/api app=ghcr.io/acme/api:v1.9.2

4. If the tag should exist, fix the publish step. Re-run the CI job’s build-and-push, and verify the push succeeded by re-listing tags. A common cause is a push that failed silently after a successful build.

5. For digest pins, re-resolve the digest. If you pin @sha256:... and it was garbage-collected, get the current digest and update the manifest:

crane digest ghcr.io/acme/api:v1.9.3
# -> sha256:abcd...  use this value in the image reference

6. For architecture mismatches, publish the missing platform. Rebuild as a multi-arch image with docker buildx build --platform linux/amd64,linux/arm64 --push, then confirm with crane manifest that the node’s platform is listed.

7. Avoid mutable tags in production. Pin to immutable digests or versioned tags so a retag/prune elsewhere cannot pull the manifest out from under a running rollout.

Prevention and Best Practices

  • Enable immutable tags on your registry so a published version can never be overwritten or pruned out from under deployments.
  • Gate deploys on a registry existence check (crane manifest/skopeo inspect) in CI before applying the manifest to the cluster.
  • Pin production workloads to digests, not floating tags like latest, so the reference is content-addressable and stable.
  • Align retention policies with your rollback window: never prune tags that any live or recently-live Deployment still references.
  • Standardize tag naming (always-with-v or always-without) across CI and manifests to eliminate prefix typos.
  • For multi-arch fleets, always build and push every node architecture in the cluster.

Frequently Asked Questions

How is manifest unknown different from repository does not exist? repository does not exist (or pull access denied) fails before tag resolution — the registry rejects the repo path or your credentials. manifest unknown means the repo is reachable and authorized, but the specific tag or digest you named has no manifest.

The tag worked yesterday and fails today — what changed? Almost always a registry retention/garbage-collection job pruned the tag, or someone retagged a mutable tag (latest) and the old manifest was cleaned up. List current tags with crane ls to confirm, and pin to immutable digests to prevent recurrence.

Can credentials cause manifest unknown? Not directly. With bad or missing credentials you get pull access denied instead. If you only have read access to some tags, though, a tag outside your scope can appear as not found — verify with a skopeo inspect using the same credentials.

My image is multi-arch and only fails on some nodes. Why? The manifest list is missing those nodes’ platform. The kubelet resolves the manifest for the node’s architecture; if arm64 is absent, that node reports the tag as not found while amd64 nodes pull fine. Rebuild with all required platforms.

Should I use tags or digests in production? Digests. A @sha256: reference is immutable and content-addressed, so it cannot be silently retagged or pruned mid-rollout. Tags are convenient for humans but should be resolved to digests at deploy time.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

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.