{"record":{"id":"bfea53fb0fe115ec","repo":"wavetermdev/waveterm","slug":"out-parameter-must-be-a-pointer-got-v-bfea53","errorCode":null,"errorMessage":"out parameter must be a pointer, got %v","messagePattern":"out parameter must be a pointer, got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tsunami/util/marshal.go","lineNumber":16,"sourceCode":"// Copyright 2025, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage util\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\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":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/tsunami/util/marshal.go#L1-L34","documentation":"MapToStruct copies a map[string]any into a struct via reflection and must be able to write through the out parameter, so out must be a non-nil pointer. If out is not a pointer kind (e.g. a struct passed by value, or a map), it returns \"out parameter must be a pointer, got %v\". Passing a non-pointer would make the decode result unobservable to the caller.","triggerScenarios":"MapToStruct(m, myStruct) (struct by value); MapToStruct(m, nil); passing an interface variable that holds a non-pointer value.","commonSituations":"Forgetting the & when passing a local struct; translating code from JSON-unmarshal helpers that accept values; calling through callCFunc with an output slot initialized as a value type.","solutions":["Pass a pointer: MapToStruct(m, &myStruct)","Ensure the variable being pointed to is the actual struct type, not a wrapped value","Initialize the out variable before the call"],"exampleFix":"// before\nvar opts Opts\nutil.MapToStruct(m, opts) // value, not pointer\n// after\nvar opts Opts\nif err := util.MapToStruct(m, &opts); err != nil { return err }","handlingStrategy":"validation","validationCode":"if out == nil || reflect.ValueOf(out).Kind() != reflect.Ptr {\n    return fmt.Errorf(\"MapToStruct needs a pointer, got %T\", out)\n}","typeGuard":"func isStructPtr(v any) bool {\n    rv := reflect.ValueOf(v)\n    return rv.Kind() == reflect.Ptr && rv.Elem().Kind() == reflect.Struct\n}","tryCatchPattern":"if err := util.MapToStruct(m, &opts); err != nil {\n    return fmt.Errorf(\"decode opts failed: %w\", err)\n}","preventionTips":["Always pass &variable when calling MapToStruct","Grep call sites for MapToStruct invocations lacking a leading &","Have component functions return typed structs so call sites decode into struct pointers naturally"],"tags":["go","reflection","pointer-required","marshaling"],"backgroundTag":"pointer-output-required","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}