kubernetes/kops · error
parsing reference for %q: %v
Error message
parsing reference for %q: %v
What it means
Same parse failure as the source-side error but for the TARGET image: name.ParseReference rejected e.TargetImage inside CopyImage.Run. The wrapper text is "parsing reference for %q: %v" so you know the destination registry/repository string, not the source, is malformed.
Source
Thrown at pkg/assets/assetcopy/copyimage.go:48
// typically used for highly secure clusters.
type CopyImage struct {
Name string
SourceImage string
TargetImage string
}
func (e *CopyImage) Run() error {
source := e.SourceImage
target := e.TargetImage
sourceRef, err := name.ParseReference(source)
if err != nil {
return fmt.Errorf("parsing reference %q: %v", source, err)
}
targetRef, err := name.ParseReference(target)
if err != nil {
return fmt.Errorf("parsing reference for %q: %v", target, err)
}
options := []remote.Option{remote.WithAuthFromKeychain(authn.DefaultKeychain)}
desc, err := remote.Get(sourceRef, options...)
if err != nil {
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.View on GitHub (pinned to 4c8573c808)
Solutions
- Correct TargetImage in the kops cluster spec to a valid reference, e.g. 'myregistry.example.com/kops/kube-apiserver:v1.28.0'.
- Remove any URL scheme (https://) and credentials from the target string; only host[:port]/repo[:tag][@digest] is allowed.
- Verify no template placeholders remain unexpanded in the target value.
- Sanity-check with `crane digest <target>` to confirm the reference parses and is reachable.
Example fix
// before
CopyImage{SourceImage: "registry.k8s.io/kops/kube-apiserver:v1.28.0", TargetImage: "https://myregistry.example.com/kops/kube-apiserver"}
// after
CopyImage{SourceImage: "registry.k8s.io/kops/kube-apiserver:v1.28.0", TargetImage: "myregistry.example.com/kops/kube-apiserver:v1.28.0"} Defensive patterns
Strategy: validation
Validate before calling
func validTargetRef(ref string) bool {
if ref == "" || strings.Contains(ref, "://") {
return false
}
_, err := name.ParseReference(ref)
return err == nil
}
if !validTargetRef(target.TargetImage) {
return fmt.Errorf("invalid TargetImage reference: %q", target.TargetImage)
} Try / catch
if err != nil {
var bad *name.ErrBadName
if errors.As(err, &bad) {
return fmt.Errorf("target image reference %q is not a valid OCI reference: %w", targetImage, err)
}
return err
} Prevention
- Always include host[:port]/repository:tag — no URL scheme, no credentials in the string.
- Mirror both source and target values together and validate the pair before running.
- Ensure the private-registry asset values are set for highly secure clusters before attempting the copy.
- Lint cluster spec assets in CI with a ParseReference check.
When it happens
Trigger: CopyImage.Run called with TargetImage that violates the container reference grammar: empty value, illegal characters, malformed tag/digest suffix, or invalid registry host (bad port, underscore, scheme prefix like 'https://').
Common situations: Typo in the target registry host in the cluster spec assets config; including a URL scheme ('https://myregistry/repo') which is not part of a reference; copying a source URL verbatim into the target field when the target registry has a different repository path/port; empty target because the private-registry asset value was never set for highly secure clusters.
Related errors
- parsing reference %q: %v
- unsupported output format: %q
- --name is required
- unknown output format: %q
- fetching %q: %v
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/e964d4909a4f667b.
Report an issue: GitHub.