kubernetes/kops · error
failed to copy image: %v
Error message
failed to copy image: %v
What it means
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.
Source
Thrown at pkg/assets/assetcopy/copyimage.go:73
return fmt.Errorf("fetching %q: %v", source, err)
}
targetDesc, err := remote.Get(targetRef, options...)
if err == nil && desc.Digest.String() == targetDesc.Digest.String() {
klog.Infof("no need to copy image from %v to %v", sourceRef, targetRef)
return nil
}
switch desc.MediaType {
case types.OCIImageIndex, types.DockerManifestList:
// Handle indexes separately.
if err := copyIndex(desc, sourceRef, targetRef, options...); err != nil {
return fmt.Errorf("failed to copy index: %v", err)
}
default:
// Assume anything else is an image, since some registries don't set mediaTypes properly.
if err := copyImage(desc, sourceRef, targetRef, options...); err != nil {
return fmt.Errorf("failed to copy image: %v", err)
}
}
return nil
}
func copyImage(desc *remote.Descriptor, sourceRef name.Reference, targetRef name.Reference, options ...remote.Option) error {
klog.Infof("copying image from %v to %v", sourceRef, targetRef)
img, err := desc.Image()
if err != nil {
return err
}
return remote.Write(targetRef, img, options...)
}
func copyIndex(desc *remote.Descriptor, sourceRef name.Reference, targetRef name.Reference, options ...remote.Option) error {
klog.Infof("copying image index from %v to %v", sourceRef, targetRef)View on GitHub (pinned to 4c8573c808)
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.
Example fix
// before $ kops ... # failed to copy image: PUT https://myregistry/v2/kops/kube-apiserver/manifests/latest: 403 Forbidden // after $ docker login myregistry.example.com $ # grant push permission to the repo, then re-run kops update cluster
Defensive patterns
Strategy: retry
Validate before calling
if out, err := exec.Command("crane", "digest", sourceImage).CombinedOutput(); err != nil {
return fmt.Errorf("source %q not pullable: %v: %s", sourceImage, err, out)
}
if err := checkPushAccess(targetRegistry); err != nil {
return err
} Try / catch
if err := e.Run(); err != nil {
if strings.Contains(err.Error(), "failed to copy image") {
if strings.Contains(err.Error(), "401") || strings.Contains(err.Error(), "403") {
// fix target-registry credentials, then retry
} else if isTransient(err) { // net timeout / connection reset
// retry with backoff; remote.Write resumes partial layer uploads
}
}
return err
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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).
Related errors
- fetching %q: %v
- failed to copy index: %v
- error pulling docker image with '%s': %v: %s
- error querying kubernetes version: %v
- error loading channel %q: %v
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/a57133c3a4883f1f.
Report an issue: GitHub.