wavetermdev/waveterm · error

cannot set value of type

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.

Solutions

  1. Align the map value's type with the field type before calling MapToStruct (convert slices/maps explicitly).
  2. Change the struct field to a type compatible with JSON-decoded shapes (e.g. []any then convert, or a custom UnmarshalJSON type).
  3. 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

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


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

Appendix: 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)