{"record":{"id":"7f32732fbef2b9e9","repo":"kubernetes/kops","slug":"cannot-set-value","errorCode":null,"errorMessage":"cannot set value","messagePattern":"cannot set value","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/pkg/reflectutils/access.go","lineNumber":116,"sourceCode":"\n\t\treturn nil\n\t}\n\n\terr = ReflectRecursive(targetValue, visitor, &ReflectOptions{JSONNames: true})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif !fieldSet {\n\t\treturn fmt.Errorf(\"field %s not found in %s\", targetPath, BuildTypeName(reflect.TypeOf(target)))\n\t}\n\n\treturn nil\n}\n\nfunc setType(v reflect.Value, newValue string) error {\n\tif !v.CanSet() {\n\t\treturn fmt.Errorf(\"cannot set value\")\n\t}\n\n\tif v.Type().Kind() == reflect.Slice {\n\t\t// To support multiple values, we split on commas.\n\t\t// We have no way to escape a comma currently; but in general we prefer having a slice in the schema,\n\t\t// rather than having values that need to be parsed, so we may not need it.\n\t\ttokens := strings.Split(newValue, \",\")\n\t\tvalueArray := reflect.MakeSlice(v.Type(), 0, v.Len()+len(tokens))\n\t\tvalueArray = reflect.AppendSlice(valueArray, v)\n\t\tfor _, s := range tokens {\n\t\t\tvalueItem := reflect.New(v.Type().Elem())\n\t\t\tif err := setType(valueItem.Elem(), s); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tvalueArray = reflect.Append(valueArray, valueItem.Elem())\n\t\t}\n\t\treflect.New(v.Type().Elem())\n\t\tv.Set(valueArray)","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/util/pkg/reflectutils/access.go#L98-L134","documentation":"setType is the low-level setter used by SetString; it refuses to write when v.CanSet() is false, meaning the reflect.Value is not addressable. This guards against mutating unexported fields or values obtained from non-pointer targets.","triggerScenarios":"SetString reaching the matched leaf through an unexported field, or being handed a non-addressable value (struct passed by value, map value, interface holding a copy).","commonSituations":"Calling SetString(&structByValue,...) where an intermediate field is unexported; using SetString on values pulled from maps or slices of non-pointer elements.","solutions":["Pass a pointer to the top-level struct to SetString.","Make the target field exported in the struct definition.","Copy the object to a locally addressable variable (&obj) before mutating."],"exampleFix":"// before\nreflectutils.SetString(cfg, \"spec.field\", \"x\")     // cfg is a struct value\n// after\nreflectutils.SetString(&cfg, \"spec.field\", \"x\")","handlingStrategy":"validation","validationCode":"v := reflect.ValueOf(target)\nif v.Kind() != reflect.Ptr || v.IsNil() {\n    return errors.New(\"target must be an addressable pointer\")\n}","typeGuard":"func isAddressable(target interface{}) bool {\n    v := reflect.ValueOf(target)\n    return v.Kind() == reflect.Ptr && v.Elem().CanSet()\n}","tryCatchPattern":"if err := SetString(&obj, path, val); err != nil {\n    if err.Error() == \"cannot set value\" || strings.Contains(err.Error(), \"cannot set value\") {\n        return fmt.Errorf(\"field %q is not settable (unexported or non-addressable)\", path)\n    }\n    return err\n}","preventionTips":["Pass pointers, not values, to SetString.","Avoid unexported fields on paths you intend to mutate.","Do not target fields inside map values."],"tags":["go","reflection","immutable-field"],"backgroundTag":"unaddressable-reflect-value","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"}