kubernetes/kops · error
cannot set field %q (marked immutable)
Error message
cannot set field %q (marked immutable)
What it means
SetString's visitor rejects setting a field when reflect reports !v.CanSet() — the value is not addressable or reached through an unexported field — and the message calls it 'marked immutable'. The library cannot write through the reflection value at that path.
Source
Thrown at util/pkg/reflectutils/access.go:48
func SetString(target interface{}, targetPath string, newValue string) error {
targetValue := reflect.ValueOf(target)
targetFieldPath, err := ParseFieldPath(targetPath)
if err != nil {
return fmt.Errorf("cannot parse field path %q: %w", targetPath, err)
}
fieldSet := false
visitor := func(path *FieldPath, field *reflect.StructField, v reflect.Value) error {
if !targetFieldPath.HasPrefixMatch(path) {
return nil
}
if targetFieldPath.Matches(path) {
if !v.CanSet() {
return fmt.Errorf("cannot set field %q (marked immutable)", path)
}
if err := setType(v, newValue); err != nil {
return fmt.Errorf("cannot set field %q: %v", path, err)
}
fieldSet = true
return nil
}
// Partial match, append the next explicitly indexed slice element.
if v.Kind() == reflect.Slice {
if len(targetFieldPath.elements) > len(path.elements) {
next := targetFieldPath.elements[len(path.elements)]
if next.Type == FieldPathElementTypeArrayIndex && next.number == v.Len() {
if !v.CanSet() {
return fmt.Errorf("cannot set field %q (marked immutable)", path)
}View on GitHub (pinned to 4c8573c808)
Solutions
- Pass a pointer to the target struct (&cluster) so reflection values are addressable
- Choose a different, settable field path — some spec fields are intentionally immutable after creation
- Recreate the resource with the desired value instead of mutating the existing one
Example fix
// before reflectutils.SetString(*cluster, "spec.kubernetesVersion", "v1.28.0") // copy, not settable // after reflectutils.SetString(cluster, "spec.kubernetesVersion", "v1.28.0") // cluster is *api.Cluster
Defensive patterns
Strategy: validation
Validate before calling
func settable(target interface{}, path string) error {
v := reflect.ValueOf(target)
if v.Kind() != reflect.Ptr || v.IsNil() {
return fmt.Errorf("target must be a non-nil pointer")
}
return nil
} Type guard
func isSettableTarget(t interface{}) bool {
v := reflect.ValueOf(t)
return v.Kind() == reflect.Ptr && !v.IsNil() && v.Elem().CanSet()
} Try / catch
if err := reflectutils.SetString(target, path, val); err != nil {
if strings.Contains(err.Error(), "marked immutable") {
return fmt.Errorf("field %s cannot be modified; recreate the resource instead", path)
}
return err
} Prevention
- Always pass pointers (&cluster), never struct copies
- Do not target unexported fields via reflection paths
- Treat 'immutable' errors as design intent: recreate instead of mutate
- Document which spec fields are editable post-creation
When it happens
Trigger: Calling SetString targeting a field inside a non-pointer struct, an unexported struct field, or a value obtained by value (not pointer) — e.g. SetString(clusterValue, ...) where clusterValue is a struct copy rather than &cluster.
Common situations: kops set / kops replace on immutable cluster fields; trying to modify fields of a struct passed by value; walking into unexported internals of the kops API types.
Related errors
- cannot set field %q: %v
- cannot unset field %q (marked immutable)
- expected slice, got %T
- conversion error for field %s: %s
- unable to convert from Quantity %v to float
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/5a98d2cb37ef5d14.
Report an issue: GitHub.