wavetermdev/waveterm · error

out parameter must be a pointer to struct, got pointer to %v

Error message

out parameter must be a pointer to struct, got pointer to %v

What it means

A second-stage guard in MapToStruct: out is a pointer, but reflect.Value.Elem() reveals it does not point to a struct (e.g. pointer to map or slice). The reflection field-walk only works on struct kinds, so the call is rejected with the pointed-to kind named.

Source

Thrown at pkg/util/utilfn/marshal.go:67

	}
	decoder, err := mapstructure.NewDecoder(dconfig)
	if err != nil {
		return err
	}
	return decoder.Decode(input)
}

func MapToStruct(in map[string]any, out any) error {
	// Check that out is a pointer
	outValue := reflect.ValueOf(out)
	if outValue.Kind() != reflect.Ptr {
		return fmt.Errorf("out parameter must be a pointer, got %v", outValue.Kind())
	}

	// Get the struct it points to
	elem := outValue.Elem()
	if elem.Kind() != reflect.Struct {
		return fmt.Errorf("out parameter must be a pointer to struct, got pointer to %v", elem.Kind())
	}

	// Get type information
	typ := elem.Type()

	// For each field in the struct
	for i := 0; i < typ.NumField(); i++ {
		field := typ.Field(i)

		// Skip unexported fields
		if !field.IsExported() {
			continue
		}

		name := getJSONName(field)
		if value, ok := in[name]; ok {
			if err := setValue(elem.Field(i), value); err != nil {
				return fmt.Errorf("error setting field %s: %w", name, err)

View on GitHub (pinned to a4447c1563)

Solutions

  1. Pass a pointer to a struct: MapToStruct(m, &cfg), not &m
  2. If the target is a **T, dereference first: MapToStruct(m, *cfgPtr)
  3. If you actually want a map out, use StructToMap instead — the functions are directional
  4. Add a Go generic constraint (out *T, T struct) so the compiler rejects wrong shapes

Example fix

// before
out := map[string]any{}
err := utilfn.MapToStruct(in, &out) // pointer to map, not struct
// after
type Config struct{ Name string `json:"name"` }
var cfg Config
err := utilfn.MapToStruct(in, &cfg)
Defensive patterns

Strategy: type-guard

Validate before calling

if !isPtrToStruct(out) {
    return errors.New("MapToStruct requires *struct")
}

Type guard

func isPtrToStruct(out any) bool {
    v := reflect.ValueOf(out)
    return v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct
}

Try / catch

if err := utilfn.MapToStruct(m, out); err != nil {
    if strings.Contains(err.Error(), "pointer to struct") {
        // destination shape is wrong; inspect %T of out
    }
}

Prevention

When it happens

Trigger: Calling MapToStruct(m, &someMap) or MapToStruct(m, &slice); passing **Config (pointer to pointer) where Elem() is a pointer, not a struct; a typed nil *Config works (Elem is struct) but a *map does not.

Common situations: Generic decode helpers receiving *map[string]any from callers who confused input and output types; refactors changing the destination type without updating MapToStruct calls; double-pointer wrapping from APIs that return *T.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/031e85cac12fae03. Report an issue: GitHub.