{"record":{"id":"a57133c3a4883f1f","repo":"kubernetes/kops","slug":"failed-to-copy-image-v","errorCode":null,"errorMessage":"failed to copy image: %v","messagePattern":"failed to copy image: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/assets/assetcopy/copyimage.go","lineNumber":73,"sourceCode":"\t\treturn fmt.Errorf(\"fetching %q: %v\", source, err)\n\t}\n\n\ttargetDesc, err := remote.Get(targetRef, options...)\n\tif err == nil && desc.Digest.String() == targetDesc.Digest.String() {\n\t\tklog.Infof(\"no need to copy image from %v to %v\", sourceRef, targetRef)\n\t\treturn nil\n\t}\n\n\tswitch desc.MediaType {\n\tcase types.OCIImageIndex, types.DockerManifestList:\n\t\t// Handle indexes separately.\n\t\tif err := copyIndex(desc, sourceRef, targetRef, options...); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to copy index: %v\", err)\n\t\t}\n\tdefault:\n\t\t// Assume anything else is an image, since some registries don't set mediaTypes properly.\n\t\tif err := copyImage(desc, sourceRef, targetRef, options...); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to copy image: %v\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc copyImage(desc *remote.Descriptor, sourceRef name.Reference, targetRef name.Reference, options ...remote.Option) error {\n\tklog.Infof(\"copying image from %v to %v\", sourceRef, targetRef)\n\n\timg, err := desc.Image()\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn remote.Write(targetRef, img, options...)\n}\n\nfunc copyIndex(desc *remote.Descriptor, sourceRef name.Reference, targetRef name.Reference, options ...remote.Option) error {\n\tklog.Infof(\"copying image index from %v to %v\", sourceRef, targetRef)","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/assets/assetcopy/copyimage.go#L55-L91","documentation":"For any source descriptor whose media type is NOT an index/manifest list, Run assumes it is a single image and calls copyImage (desc.Image() then remote.Write to the target); failures are wrapped as \"failed to copy image: %v\". This covers both errors building the v1.Image from the source descriptor and errors writing layers/config/manifest to the target registry.","triggerScenarios":"Single-image (non-index) source; desc.Image() fails to load the manifest/config from the source registry, or remote.Write fails pushing config, layers, or the final manifest to the target: unauthorized, manifest/blob PUT rejected, quota exceeded, connection reset mid-layer upload, or schema-2 media types unsupported by the target.","commonSituations":"Missing or expired credentials for the private target registry; target registry read-only or over quota; flaky network cutting off a large layer upload; copying very old (schema1) or unusual images into a registry that rejects their media types; pulling from source succeeded earlier but the blob is now gone (retention policy on source).","solutions":["Check target registry auth: `docker login <target>` and ensure the credentials are in the default keychain kops uses.","Re-run the copy; remote.Write resumes incomplete layer uploads, so transient network errors often resolve on retry.","Verify target registry capacity/quotas and that it accepts the image's media types (schema2/OCI).","Read the inner error to identify the failing blob or manifest; confirm it still exists on the source registry."],"exampleFix":"// before\n$ kops ... # failed to copy image: PUT https://myregistry/v2/kops/kube-apiserver/manifests/latest: 403 Forbidden\n// after\n$ docker login myregistry.example.com\n$ # grant push permission to the repo, then re-run kops update cluster","handlingStrategy":"retry","validationCode":"if out, err := exec.Command(\"crane\", \"digest\", sourceImage).CombinedOutput(); err != nil {\n\treturn fmt.Errorf(\"source %q not pullable: %v: %s\", sourceImage, err, out)\n}\nif err := checkPushAccess(targetRegistry); err != nil {\n\treturn err\n}","typeGuard":null,"tryCatchPattern":"if err := e.Run(); err != nil {\n\tif strings.Contains(err.Error(), \"failed to copy image\") {\n\t\tif strings.Contains(err.Error(), \"401\") || strings.Contains(err.Error(), \"403\") {\n\t\t\t// fix target-registry credentials, then retry\n\t\t} else if isTransient(err) { // net timeout / connection reset\n\t\t\t// retry with backoff; remote.Write resumes partial layer uploads\n\t\t}\n\t}\n\treturn err\n}","preventionTips":["Authenticate to the target registry (docker login) before running kops update.","Monitor target registry quota; clean old layers if near the storage limit.","Retry failed copies — remote.Write resumes incomplete blob uploads.","Pin sources by digest and confirm they still exist before copying."],"tags":["container-image","registry","push","network"],"backgroundTag":"image-push-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}