{"record":{"id":"23b531a833db69c0","repo":"wavetermdev/waveterm","slug":"out-parameter-must-be-a-pointer-got-v","errorCode":null,"errorMessage":"out parameter must be a pointer, got %v","messagePattern":"out parameter must be a pointer, got (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/util/utilfn/marshal.go","lineNumber":61,"sourceCode":"\n// does a mapstructure using \"json\" tags\nfunc DoMapStructure(out any, input any) error {\n\tdconfig := &mapstructure.DecoderConfig{\n\t\tResult:  out,\n\t\tTagName: \"json\",\n\t}\n\tdecoder, err := mapstructure.NewDecoder(dconfig)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn decoder.Decode(input)\n}\n\nfunc MapToStruct(in map[string]any, out any) error {\n\t// Check that out is a pointer\n\toutValue := reflect.ValueOf(out)\n\tif outValue.Kind() != reflect.Ptr {\n\t\treturn fmt.Errorf(\"out parameter must be a pointer, got %v\", outValue.Kind())\n\t}\n\n\t// Get the struct it points to\n\telem := outValue.Elem()\n\tif elem.Kind() != reflect.Struct {\n\t\treturn fmt.Errorf(\"out parameter must be a pointer to struct, got pointer to %v\", elem.Kind())\n\t}\n\n\t// Get type information\n\ttyp := elem.Type()\n\n\t// For each field in the struct\n\tfor i := 0; i < typ.NumField(); i++ {\n\t\tfield := typ.Field(i)\n\n\t\t// Skip unexported fields\n\t\tif !field.IsExported() {\n\t\t\tcontinue","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/util/utilfn/marshal.go#L43-L79","documentation":"MapToStruct uses reflection to copy a map[string]any into a struct, but reflection can only write through the out parameter if it is a pointer. This guard fires when out is a struct value (or any non-pointer), because writing to it would modify a copy and be lost. The error names the actual reflect.Kind received.","triggerScenarios":"Calling MapToStruct(m, myStruct) passing a struct value instead of &myStruct; passing a map, slice, or interface holding a non-pointer; passing an untyped nil as out.","commonSituations":"Copy-paste from StructToMap call sites (which take values); forgetting the & when the destination is a local variable; wrapping generic decode helpers that accept any.","solutions":["Pass a pointer to the destination struct: MapToStruct(m, &cfg)","If the value is addressable already, take its address before the call","In generic/helper wrappers, require T any with a *T argument or reflect-check and return a clear compile-time-friendly API","Add the guard message to your lint/test expectations so regressions fail fast"],"exampleFix":"// before\nvar cfg Config\nerr := utilfn.MapToStruct(raw, cfg) // out parameter must be a pointer, got struct\n// after\nvar cfg Config\nerr := utilfn.MapToStruct(raw, &cfg)","handlingStrategy":"validation","validationCode":"func checkOutPtr(out any) error {\n    if out == nil { return errors.New(\"out is nil\") }\n    if reflect.ValueOf(out).Kind() != reflect.Ptr {\n        return fmt.Errorf(\"out must be a pointer, got %T\", out)\n    }\n    return nil\n}","typeGuard":"func isPtrToStruct(out any) bool {\n    v := reflect.ValueOf(out)\n    return v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct\n}","tryCatchPattern":"if err := utilfn.MapToStruct(m, out); err != nil {\n    if strings.Contains(err.Error(), \"must be a pointer\") {\n        // fix call site: pass &dest\n    }\n}","preventionTips":["Always pass &dest to MapToStruct","Constrain helper generics to *T where possible","Unit-test reflection helpers with wrong-type inputs"],"tags":["reflection","go","marshaling","validation"],"backgroundTag":"pointer-required-argument","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}