docker/cli · error

invalid named reference bytes

Error message

invalid named reference bytes: %s: %w

What it means

Returned by SerializableNamed.UnmarshalJSON (types.go:144) when the JSON bytes cannot be unmarshaled into a plain string. SerializableNamed wraps a reference.Named and expects its JSON representation to be a quoted string (the image reference), so any non-string JSON (object, number, array, malformed bytes) fails json.Unmarshal and is wrapped here. The raw bytes are printed for diagnosis.

Solutions

  1. Validate the JSON before unmarshaling: ensure the Ref field is a JSON string.
  2. Delete the malformed cached manifest and re-fetch it from the registry.
  3. If you control serialization, always emit Ref as the string form of the reference (MarshalJSON does json.Marshal(s.String())).
  4. Use json.Decoder with DisallowUnknownFields during development to catch schema drift early.

Example fix

// before: unmarshaling trust-unchecked bytes
json.Unmarshal(data, &img)

// after: validate Ref is a string first
var probe map[string]json.RawMessage
_ = json.Unmarshal(data, &probe)
if v, ok := probe["Ref"]; ok && len(v) > 0 && v[0] != '"' {
    return fmt.Errorf("Ref must be a JSON string, got %s", v)
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate the Ref field is a JSON string before unmarshaling into ImageManifest
var probe map[string]json.RawMessage
if err := json.Unmarshal(data, &probe); err != nil {
    return err
}
if v, ok := probe["Ref"]; ok && (len(v) == 0 || v[0] != '"') {
    return fmt.Errorf("Ref must be a JSON string, got %s", string(v))
}

Try / catch

// Catch the unmarshal error and purge corrupt cache
if err := json.Unmarshal(data, &im); err != nil {
    if strings.Contains(err.Error(), "invalid named reference bytes") {
        _ = os.Remove(filename) // drop corrupt manifest cache
    }
    return err
}

Prevention

When it happens

Trigger: Deserializing an ImageManifest from JSON whose "Ref" field is not a JSON string — e.g. it is a nested object, null, a bare number, or the file is truncated/corrupted. Also triggered by a version mismatch where an older/newer format serialized Ref differently than a plain string.

Common situations: Hand-editing a cached manifest file and putting an object where a string is expected, a corrupt ~/.docker/manifests entry, or a tool that emits ImageManifest JSON with a non-string Ref representation.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/18a111c0c58daa27. Report an issue: GitHub.

Appendix: source

Thrown at cli/manifest/types/types.go:144

	return ImageManifest{
		Ref:         &SerializableNamed{Named: ref},
		Descriptor:  desc,
		Raw:         raw,
		OCIManifest: manifest,
	}
}

// SerializableNamed is a reference.Named that can be serialized and deserialized
// from JSON
type SerializableNamed struct {
	reference.Named
}

// UnmarshalJSON loads the Named reference from JSON bytes
func (s *SerializableNamed) UnmarshalJSON(b []byte) error {
	var raw string
	if err := json.Unmarshal(b, &raw); err != nil {
		return fmt.Errorf("invalid named reference bytes: %s: %w", b, err)
	}
	var err error
	s.Named, err = reference.ParseNamed(raw)
	return err
}

// MarshalJSON returns the JSON bytes representation
func (s *SerializableNamed) MarshalJSON() ([]byte, error) {
	return json.Marshal(s.String())
}

View on GitHub (pinned to 4f84911bfe)