{"record":{"id":"a3158f51fc1f5381","repo":"GoogleContainerTools/skaffold","slug":"statuscheck-image-pull-err","errorCode":"STATUSCHECK_IMAGE_PULL_ERR","errorMessage":"container %s is waiting to start: %s can't be pulled","messagePattern":"container (.+?) is waiting to start: (.+?) can't be pulled","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/diag/validator/validator.go","lineNumber":371,"sourceCode":"\t}\n\treturn fmt.Sprintf(actionableMessage, p.namespace, p.name)\n}\n\nfunc extractErrorMessageFromWaitingContainerStatus(po *v1.Pod, c v1.ContainerStatus) (proto.StatusCode, []string, error) {\n\t// Extract meaning full error out of container statuses.\n\tswitch c.State.Waiting.Reason {\n\tcase podInitializing:\n\t\t// container is waiting to run. This could be because one of the init containers is\n\t\t// still not completed\n\t\treturn proto.StatusCode_STATUSCHECK_POD_INITIALIZING, nil, nil\n\tcase containerCreating:\n\t\treturn proto.StatusCode_STATUSCHECK_CONTAINER_CREATING, nil, fmt.Errorf(\"creating container %s\", c.Name)\n\tcase crashLoopBackOff:\n\t\t// TODO, in case of container restarting, return the original failure reason due to which container failed.\n\t\tsc, l := getPodLogs(po, c.Name, proto.StatusCode_STATUSCHECK_CONTAINER_RESTARTING)\n\t\treturn sc, l, fmt.Errorf(\"container %s is backing off waiting to restart\", c.Name)\n\tcase ImagePullErr, ImagePullBackOff, ErrImagePullBackOff:\n\t\treturn proto.StatusCode_STATUSCHECK_IMAGE_PULL_ERR, nil, fmt.Errorf(\"container %s is waiting to start: %s can't be pulled\", c.Name, c.Image)\n\tcase runContainerError:\n\t\tmatch := runContainerRe.FindStringSubmatch(c.State.Waiting.Message)\n\t\tif len(match) != 0 {\n\t\t\treturn proto.StatusCode_STATUSCHECK_RUN_CONTAINER_ERR, nil, fmt.Errorf(\"container %s in error: %s\", c.Name, trimSpace(match[3]))\n\t\t}\n\t}\n\tlog.Entry(context.TODO()).Debugf(\"Unknown waiting reason for container %q: %v\", c.Name, c.State)\n\treturn proto.StatusCode_STATUSCHECK_CONTAINER_WAITING_UNKNOWN, nil, fmt.Errorf(\"container %s in error: %v\", c.Name, c.State.Waiting)\n}\n\nfunc newPodStatus(n string, ns string, p string) *podStatus {\n\treturn &podStatus{\n\t\tname:      n,\n\t\tnamespace: ns,\n\t\tphase:     p,\n\t\tae: proto.ActionableErr{\n\t\t\tErrCode: proto.StatusCode_STATUSCHECK_SUCCESS,\n\t\t},","sourceCodeStart":353,"sourceCodeEnd":389,"githubUrl":"https://github.com/GoogleContainerTools/skaffold/blob/a1189de023efc32d4b8e11f395acc678aa555011/pkg/diag/validator/validator.go#L353-L389","documentation":"Raised when a container's Waiting state has reason ImagePullBackOff or ErrImagePull (code STATUSCHECK_IMAGE_PULL_ERR): the kubelet cannot pull the container image, so the container can never start. The message names the container and its image.","triggerScenarios":"extractErrorMessageFromWaitingContainerStatus matches ImagePullErr/ImagePullBackOff/ErrImagePullBackOff in the Waiting reason and returns 'container <name> is waiting to start: <image> can't be pulled'.","commonSituations":"Typo in image name/tag, private registry without imagePullSecrets, expired registry credentials, rate limiting (Docker Hub), image not present on air-gapped cluster, wrong architecture manifest.","solutions":["Verify the image reference (registry/repo:tag) is correct and the tag actually exists (docker pull or curl the registry).","Create/attach imagePullSecrets: kubectl create secret docker-registry regcred ... and reference it in the pod spec.","Fix registry auth on the node (~/.docker/config.json, credential helpers, or node-level mirror config).","Check architecture/OS match (amd64 vs arm64) and, for rate limits, use a mirror or authenticated pulls."],"exampleFix":"// before: private image without credentials\n// image: gcr.io/my-proj/app:latest\n// after: with secret attached\n// imagePullSecrets: [{name: gcr-key}]\n// image: gcr.io/my-proj/app:v1.2.3","handlingStrategy":"validation","validationCode":"img := pod.Spec.Containers[0].Image; if err := registry.CheckImageExists(ctx, img, pullSecrets); err != nil { return fmt.Errorf(\"image %s not pullable: %w\", img, err) }","typeGuard":"func isImagePullError(cs v1.ContainerStatus) bool { r := cs.State.Waiting != nil && cs.State.Waiting.Reason; return r == \"ImagePullBackOff\" || r == \"ErrImagePull\" }","tryCatchPattern":"sc, _, err := getContainerStatus(pod, cs); if sc == proto.StatusCode_STATUSCHECK_IMAGE_PULL_ERR { return fmt.Errorf(\"fix image ref/credentials for %s before retrying\", cs.Name) } // do not blind-retry","preventionTips":["Pin digests or immutable tags; never rely on :latest in prod","Attach imagePullSecrets to every service account that deploys","Pre-pull or mirror images for air-gapped/restricted clusters","Verify image architecture matches node (amd64/arm64)"],"tags":["kubernetes","image-pull","registry","container"],"backgroundTag":"imagepullbackoff","analyzedSha":"a1189de023efc32d4b8e11f395acc678aa555011","analyzedAt":"2026-09-05T12:09:27.064Z","contentChangedAt":"2026-09-05T12:09:27.064Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}