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 MapToStruct's field-assignment helper. After trying direct assignment and ConvertibleTo-based conversion, it gives up if the input value's type still cannot be stored in the field type, reporting both types. Non-convertible cases include string→slice, map→struct, and different named types without convertible underlying kinds.

Source

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

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

// DecodeDataURL decodes a data URL and returns the mimetype and raw data bytes
func DecodeDataURL(dataURL string) (mimeType string, data []byte, err error) {
	if !strings.HasPrefix(dataURL, "data:") {
		return "", nil, fmt.Errorf("invalid data URL: must start with 'data:'")
	}

	parts := strings.SplitN(dataURL, ",", 2)
	if len(parts) != 2 {
		return "", nil, fmt.Errorf("invalid data URL format: missing comma separator")
	}

	header := parts[0]
	dataStr := parts[1]

	// Parse mimetype from header: "data:text/plain;base64" -> "text/plain"
	headerWithoutPrefix := strings.TrimPrefix(header, "data:")

View on GitHub (pinned to a4447c1563)

Solutions

  1. Convert the value in the caller to the exact field type before calling MapToStruct (strconv, json.Unmarshal into the target, etc.)
  2. Implement UnmarshalJSON on custom field types if the data shape is fixed but the representation is loose
  3. Use encoding/json's map→struct path (json.Marshal then json.Unmarshal) which handles more coercions, if performance allows
  4. Align the struct field type with the real data type (e.g. use json.Number or string fields for stringly-typed sources)

Example fix

// before
raw := map[string]any{"tags": "a,b"} // Tags []string
var cfg Config
utilfn.MapToStruct(raw, &cfg) // cannot set value of type string to field of type []string
// after
raw["tags"] = strings.Split("a,b", ",")
utilfn.MapToStruct(raw, &cfg) // ok
Defensive patterns

Strategy: validation

Validate before calling

func canSet(field reflect.Value, val any) bool {
    v := reflect.ValueOf(val)
    return v.Type().AssignableTo(field.Type()) || v.Type().ConvertibleTo(field.Type())
}

Try / catch

if err := utilfn.MapToStruct(in, &cfg); err != nil {
    if strings.Contains(err.Error(), "cannot set value of type") {
        // coerce the offending value manually and retry
    }
}

Prevention

When it happens

Trigger: Setting []string field from a string value; bool field from "true" string (strconv not attempted); time.Time field from an int64 timestamp; named type mismatch where ConvertibleTo is false (e.g. func/map kinds).

Common situations: Loosely typed config formats (YAML/TOML parsers yielding map[string]any of strings) feeding strictly typed structs; version drift where a struct field changed type; hand-built maps with JSON-ish values of wrong types.

Related errors


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