wavetermdev/waveterm · error

error setting field

Error message

error setting field %s: %w

What it means

MapToStruct copies values from a map[string]any into struct fields via reflection. This error wraps the underlying setValue failure (type mismatch, unassignable/convertible types) with the JSON field name that failed, so you know exactly which key in the map could not be mapped into the destination struct.

Solutions

  1. Read the wrapped field name in the error and fix the value's type in the map (or use encoding/json.Unmarshal, which has richer unmarshaling rules) so it matches the struct field type.
  2. Change the struct field type to match the incoming data (e.g. int -> float64, string -> []string) or add a custom type with UnmarshalJSON.
  3. Pre-normalize the map before calling MapToStruct (coerce numbers with FromFloat64-style helpers, convert nested maps).

Example fix

// before
var cfg Config
err := util.MapToStruct(map[string]any{"port": "8080"}, &cfg) // error setting field port
// after
port, _ := strconv.Atoi("8080")
err := util.MapToStruct(map[string]any{"port": port}, &cfg)
Defensive patterns

Strategy: try-catch

Validate before calling

func validateMapping(in map[string]any, out any) error {
    v := reflect.ValueOf(out).Elem().Type()
    for i := 0; i < v.NumField(); i++ {
        name := v.Field(i).Name
        if tag := v.Field(i).Tag.Get("json"); tag != "" && tag != "-" {
            name = strings.Split(tag, ",")[0]
        }
        if val, ok := in[name]; ok && val != nil {
            if reflect.TypeOf(val) != reflect.TypeOf(v.Field(i)) {
                return fmt.Errorf("field %s: value type %T may not map to %s", name, val, v.Field(i).Type)
            }
        }
    }
    return nil
}

Try / catch

if err := util.MapToStruct(in, &cfg); err != nil {
    var fieldErr string
    if _, scanErr := fmt.Sscanf(err.Error(), "error setting field %s", &fieldErr); scanErr == nil {
        log.Printf("bad value for field %q, using defaults", fieldErr)
    }
    return fmt.Errorf("config mapping failed: %w", err)
}

Prevention

When it happens

Trigger: Call util.MapToStruct(in, &outStruct) where in contains a key matching a struct field's json tag (or Go field name), but the value's dynamic type is not assignable or convertible to the field's type (e.g. string into int, []any into []string, nested map into a non-struct field).

Common situations: Decoding loosely-typed config (YAML/TOML parsed as map[string]any) into typed structs; JSON numbers arriving as float64 into int fields after a numeric-type change; schema drift where an API returns a string but the struct expects a slice or struct.

Related errors


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

Appendix: source

Thrown at tsunami/util/marshal.go:40

		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)
			}
		}
	}

	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())
	}

View on GitHub (pinned to a4447c1563)