kubernetes/kops · error

field %q in %s was not an object, was %T

Error message

field %q in %s was not an object, was %T

What it means

While walking the dotted field path, Reparse requires each intermediate value to be a map[string]interface{} so it can continue descending. If a segment exists but holds a scalar, list, or other non-object type, this error reports the field, full path, and the actual Go type found.

Source

Thrown at pkg/kubemanifest/manifest.go:233

		return ""
	}
	return s
}

// Reparse parses a subfield from an object
func (m *Object) Reparse(obj interface{}, fields ...string) error {
	humanFields := strings.Join(fields, ".")

	current := m.data
	for _, field := range fields {
		v, found := current[field]
		if !found {
			return fmt.Errorf("field %q in %s not found", field, humanFields)
		}

		m, ok := v.(map[string]interface{})
		if !ok {
			return fmt.Errorf("field %q in %s was not an object, was %T", field, humanFields, v)
		}
		current = m
	}

	b, err := yaml.Marshal(current)
	if err != nil {
		return fmt.Errorf("error marshaling %s to yaml: %v", humanFields, err)
	}

	if err := yaml.Unmarshal(b, obj); err != nil {
		return fmt.Errorf("error unmarshaling subobject %s: %v", humanFields, err)
	}

	return nil
}

// Set mutates a subfield to the newValue
func (m *Object) Set(newValue interface{}, fieldPath ...string) error {

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Adjust the fields path to stop before non-object segments (walk lists separately)
  2. Verify the manifest schema/version matches the expected nesting
  3. Filter objects to the intended kind before Reparse
  4. Inspect the manifest's structure at the reported path (the error prints the actual %T)

Example fix

// before: path walks into a list
obj.Reparse([]string{"spec","containers"}, &v) // containers is []interface{}
// after: reparse the pod spec level instead
obj.Reparse([]string{"spec","template","spec"}, &podSpec)
Defensive patterns

Strategy: validation

Validate before calling

func pathIsObject(obj *kubemanifest.Object, path ...string) bool {
	cur, _ := obj.ToJSONMap()
	for i, f := range path {
		v, ok := cur[f]
		if !ok { return false }
		if i == len(path)-1 { return true } // last segment may be target struct
		m, ok := v.(map[string]interface{})
		if !ok { return false }
		cur = m
	}
	return true
}

Type guard

func isObjectMap(v interface{}) bool {
	_, ok := v.(map[string]interface{})
	return ok
}

Try / catch

err := obj.Reparse(fields, &target)
if err != nil && strings.Contains(err.Error(), "was not an object") {
	return fmt.Errorf("unexpected manifest shape at %v: %w", fields, err)
}

Prevention

When it happens

Trigger: Calling Reparse with a path where an intermediate segment is not a nested object — e.g. path spec.template on a manifest where template is a string, or path through a list-valued field (lists can't be traversed by map key).

Common situations: Wrong field path through schema versions where a field changed type; attempting to walk into arrays (e.g. spec.containers) which are slices, not maps; manifests produced by another tool with unexpected shapes.

Related errors


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