wavetermdev/waveterm · error
cannot set value of type %v to field of type %v
Error message
cannot set value of type %v to field of type %v
What it means
setValue is the reflection helper behind MapToStruct. After direct assignment, assignability, pointer-addressing, and convertibility checks all fail, it reports that the value's dynamic type cannot be stored in the destination field type. Structs with same-layout mismatched types (e.g. named string types in different packages, map into slice) land here.
Source
Thrown at tsunami/util/marshal.go:120
// Check if types are assignable
if valueRef.Type().AssignableTo(field.Type()) {
field.Set(valueRef)
return nil
}
// If field is pointer and value isn't already a pointer, try address
if field.Kind() == reflect.Ptr && valueRef.Kind() != reflect.Ptr {
return setValue(field, valueRef.Addr().Interface())
}
// Try conversion if types are convertible
if valueRef.Type().ConvertibleTo(field.Type()) {
field.Set(valueRef.Convert(field.Type()))
return nil
}
return fmt.Errorf("cannot set value of type %v to field of type %v", valueRef.Type(), field.Type())
}View on GitHub (pinned to a4447c1563)
Solutions
- Align the map value's type with the field type before calling MapToStruct (convert slices/maps explicitly).
- Change the struct field to a type compatible with JSON-decoded shapes (e.g. []any then convert, or a custom UnmarshalJSON type).
- If the types should be convertible but aren't, check for named-type/kind mismatches and add an explicit conversion step.
Example fix
// before
m := map[string]any{"tags": []any{"a", "b"}}
util.MapToStruct(m, &cfg) // Tags []string fails
// after
m["tags"] = []string{"a", "b"}
util.MapToStruct(m, &cfg) Defensive patterns
Strategy: validation
Validate before calling
func setValueSafe(field reflect.Value, value any) (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("cannot set %T into %s", value, field.Type())
}
}()
if value != nil && reflect.TypeOf(value).ConvertibleTo(field.Type()) {
field.Set(reflect.ValueOf(value).Convert(field.Type()))
}
return nil
} Type guard
func fieldCompatible(value any, field reflect.Value) bool {
if value == nil { return true }
vt := reflect.TypeOf(value)
return vt == field.Type() || vt.AssignableTo(field.Type()) || vt.ConvertibleTo(field.Type())
} Try / catch
if err := util.MapToStruct(in, &out); err != nil {
if strings.Contains(err.Error(), "cannot set value of type") {
return normalizeAndRetry(in, &out) // coerce types then retry once
}
return err
} Prevention
- Normalize JSON-decoded data (float64 numbers, []any, map[string]any) to concrete types before mapping
- Change struct field types in lockstep with data producers
- Add custom UnmarshalJSON for time.Time or named types fed from generic JSON
When it happens
Trigger: MapToStruct encounters a value whose type is neither equal, assignable, addressable-for-pointer, nor convertible to the field type: e.g. map[string]any into a []string field, json.Number into time.Time, two distinct named types with different underlying kinds.
Common situations: Round-tripping data through JSON (everything becomes float64/string/bool/[]any/map[string]any) into structs with typed slices, nested structs, or time.Time fields; refactoring a field type without updating producers.
Related errors
- error setting field %s: %w
- cannot set value of type %v to field of type %v
- Component function must be a function
- error setting field %s: %w
- convertFileUIMessagePart expects 'file' type, got '%s'
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/6ceb0d8dbf9ccd03.
Report an issue: GitHub.