wavetermdev/waveterm · error

input must be a struct or pointer to struct, got %v

Error message

input must be a struct or pointer to struct, got %v

What it means

StructToMap converts a struct to map[string]any via reflection; after dereferencing one pointer level, the value must be a struct kind. This error reports the actual kind when the input is a map, slice, primitive, or a double pointer whose dereference is still not a struct.

Source

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

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

	return nil
}

func StructToMap(in any) (map[string]any, error) {
	// Get value and handle pointer
	val := reflect.ValueOf(in)
	if val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	// Check that we have a struct
	if val.Kind() != reflect.Struct {
		return nil, fmt.Errorf("input must be a struct or pointer to struct, got %v", val.Kind())
	}

	// Get type information
	typ := val.Type()
	out := make(map[string]any)

	// 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)
		out[name] = val.Field(i).Interface()
	}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Pass the struct itself or a single pointer to it: StructToMap(&cfg) or StructToMap(cfg)
  2. If you have a map already, you don't need conversion — use it directly or call MapToStruct for the opposite direction
  3. Constrain generics with [T any] + a runtime struct check, or [T struct] style patterns where possible
  4. Dereference extra pointer layers before the call if your data comes from *T producers

Example fix

// before
m, err := utilfn.StructToMap(rawMap) // input must be a struct or pointer to struct, got map
// after
type Config struct{ Name string `json:"name"` }
var cfg Config
m, err := utilfn.StructToMap(&cfg)
Defensive patterns

Strategy: type-guard

Validate before calling

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

Type guard

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

Try / catch

m, err := utilfn.StructToMap(v)
if err != nil && strings.Contains(err.Error(), "must be a struct") {
    // wrong helper or wrong type: check %T of v
}

Prevention

When it happens

Trigger: Calling StructToMap(someMap) (wrong direction — that's MapToStruct's job); passing a *[]T or **T; passing nil interface; passing a primitive like an int or string.

Common situations: Swapping the two helper functions by mistake in serialization glue; generic code where the type parameter isn't constrained to structs; passing results of another reflection-based call straight back in.

Related errors


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