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

After confirming out is a pointer, MapToStruct checks that the pointed-to value is a struct, because field-by-field reflection only works on struct kinds. A pointer to a map, slice, string, or other non-struct kind yields "out parameter must be a pointer to struct, got pointer to %v".

Source

Thrown at tsunami/util/marshal.go:22

package util

import (
	"fmt"
	"reflect"
	"strings"
)

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. Declare the out target as a struct (or pointer to struct) whose json tags match the map keys
  2. If the target is a map, skip MapToStruct and index the map directly
  3. For slices, write a dedicated loop or change the call site to decode into a struct

Example fix

// before
var out map[string]any
util.MapToStruct(m, &out) // pointer to map, not struct
// after
type result struct {
    Name string `json:"name"`
    Size int    `json:"size"`
}
var out result
if err := util.MapToStruct(m, &out); err != nil { return err }
Defensive patterns

Strategy: validation

Validate before calling

rv := reflect.ValueOf(out)
if rv.Kind() == reflect.Ptr && rv.Elem().Kind() != reflect.Struct {
    return fmt.Errorf("target must be *struct, got *%v", rv.Elem().Kind())
}

Type guard

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

Try / catch

if err := util.MapToStruct(m, &result); err != nil {
    return fmt.Errorf("decode failed (need *struct target): %w", err)
}

Prevention

When it happens

Trigger: MapToStruct(m, &someMap) with someMap of type map[string]any; MapToStruct(m, &someSlice); MapToStruct(m, &str).

Common situations: Trying to reuse MapToStruct as a generic map-to-value decoder for maps/slices; passing &out where out is already map[string]any from a JSON decode; mismatch between the component function's return type and the caller's decode target.

Related errors


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