{"record":{"id":"5a98d2cb37ef5d14","repo":"kubernetes/kops","slug":"cannot-set-field-q-marked-immutable","errorCode":null,"errorMessage":"cannot set field %q (marked immutable)","messagePattern":"cannot set field %q \\(marked immutable\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/pkg/reflectutils/access.go","lineNumber":48,"sourceCode":"\nfunc SetString(target interface{}, targetPath string, newValue string) error {\n\ttargetValue := reflect.ValueOf(target)\n\n\ttargetFieldPath, err := ParseFieldPath(targetPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot parse field path %q: %w\", targetPath, err)\n\t}\n\n\tfieldSet := false\n\n\tvisitor := func(path *FieldPath, field *reflect.StructField, v reflect.Value) error {\n\t\tif !targetFieldPath.HasPrefixMatch(path) {\n\t\t\treturn nil\n\t\t}\n\n\t\tif targetFieldPath.Matches(path) {\n\t\t\tif !v.CanSet() {\n\t\t\t\treturn fmt.Errorf(\"cannot set field %q (marked immutable)\", path)\n\t\t\t}\n\n\t\t\tif err := setType(v, newValue); err != nil {\n\t\t\t\treturn fmt.Errorf(\"cannot set field %q: %v\", path, err)\n\t\t\t}\n\n\t\t\tfieldSet = true\n\t\t\treturn nil\n\t\t}\n\n\t\t// Partial match, append the next explicitly indexed slice element.\n\t\tif v.Kind() == reflect.Slice {\n\t\t\tif len(targetFieldPath.elements) > len(path.elements) {\n\t\t\t\tnext := targetFieldPath.elements[len(path.elements)]\n\t\t\t\tif next.Type == FieldPathElementTypeArrayIndex && next.number == v.Len() {\n\t\t\t\t\tif !v.CanSet() {\n\t\t\t\t\t\treturn fmt.Errorf(\"cannot set field %q (marked immutable)\", path)\n\t\t\t\t\t}","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/util/pkg/reflectutils/access.go#L30-L66","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nreflectutils.SetString(*cluster, \"spec.kubernetesVersion\", \"v1.28.0\") // copy, not settable\n// after\nreflectutils.SetString(cluster, \"spec.kubernetesVersion\", \"v1.28.0\") // cluster is *api.Cluster","handlingStrategy":"validation","validationCode":"func settable(target interface{}, path string) error {\n\tv := reflect.ValueOf(target)\n\tif v.Kind() != reflect.Ptr || v.IsNil() {\n\t\treturn fmt.Errorf(\"target must be a non-nil pointer\")\n\t}\n\treturn nil\n}","typeGuard":"func isSettableTarget(t interface{}) bool {\n\tv := reflect.ValueOf(t)\n\treturn v.Kind() == reflect.Ptr && !v.IsNil() && v.Elem().CanSet()\n}","tryCatchPattern":"if err := reflectutils.SetString(target, path, val); err != nil {\n\tif strings.Contains(err.Error(), \"marked immutable\") {\n\t\treturn fmt.Errorf(\"field %s cannot be modified; recreate the resource instead\", path)\n\t}\n\treturn err\n}","preventionTips":["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"],"tags":["reflection","immutability","setstring"],"backgroundTag":"field-not-settable","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}