kubernetes/kops · error

unhandled type at path %q: %T

Error message

unhandled type at path %q: %T

What it means

Transformer.visitAny only knows how to walk map[string]any, []any, string, int64, float64, bool, and nil. A value of any other Go type inside the tree (int, json.Number, custom structs, time.Time, etc.) cannot be transformed and produces this error naming the offending type and its JSON path. Trees are normally produced by decoding into map[string]any with encoding/json, which cannot produce such types, so this indicates values were inserted programmatically or decoded differently (e.g. yaml.v3 yields map[string]any but can yield int for small numbers).

Source

Thrown at pkg/jsonutils/transform.go:76

// visitAny is a helper function that visits any value in the JSON tree
func (o *Transformer) visitAny(v any, path string) (any, error) {
	if v == nil {
		return v, nil
	}
	switch v := v.(type) {
	case map[string]any:
		if err := o.visitMap(v, path); err != nil {
			return nil, err
		}
		return v, nil
	case []any:
		return o.visitSlice(v, path)
	case int64, float64, bool:
		return o.visitPrimitive(v, path)
	case string:
		return o.visitString(v, path)
	default:
		return nil, fmt.Errorf("unhandled type at path %q: %T", path, v)
	}
}

func (o *Transformer) visitMap(m map[string]any, path string) error {
	for _, fn := range o.objectTransforms {
		if err := fn(path, m); err != nil {
			return err
		}
	}

	for k, v := range m {
		childPath := path + "." + k

		v2, err := o.visitAny(v, childPath)
		if err != nil {
			return err
		}
		m[k] = v2

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Normalize the tree before Transform: convert all numbers to int64/float64 (e.g. re-marshal with encoding/json into map[string]any).
  2. If the tree came from YAML, convert int values to int64 in a pre-pass.
  3. Extend the switch in visitAny to handle the extra type if you control the library.

Example fix

// before
var m map[string]any
yaml.Unmarshal(data, &m)
t.Transform(m) // int values fail
// after
j, _ := json.Marshal(m)
var m2 map[string]any
json.Unmarshal(j, &m2) // numbers become float64
t.Transform(m2)
Defensive patterns

Strategy: validation

Validate before calling

func normalizeJSONTypes(v any) (any, error) {
	j, err := json.Marshal(v)
	if err != nil {
		return nil, err
	}
	var out any
	if err := json.Unmarshal(j, &out); err != nil {
		return nil, err
	}
	return out, nil
}
// round-trip the tree through JSON before Transformer.Transform

Type guard

func isTransformable(v any) bool {
	switch v.(type) {
	case nil, map[string]any, []any, string, int64, float64, bool:
		return true
	}
	return false
}

Try / catch

if err := transformer.Transform(tree); err != nil {
	return fmt.Errorf("transform failed: %w", err)
}

Prevention

When it happens

Trigger: Calling Transformer.Transform on a tree built from yaml.v3 Unmarshal (small integers become int, not int64), on a tree containing json.Number values, or after inserting typed values (structs, time.Time) into the map.

Common situations: Transforming YAML-derived config (kOps manifests loaded via YAML) where integer values decode as int; mixing json.Decoder(UseNumber) output with the Transformer.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/d872b06a94041712. Report an issue: GitHub.