wavetermdev/waveterm · error
failed to adapt type from %T => %T: %w
Error message
failed to adapt type from %T => %T: %w
What it means
Second half of the JSON round-trip in AtomImpl.SetVal: json.Marshal succeeded but json.Unmarshal into the target type T failed, meaning the value's JSON shape does not fit T. This is a type mismatch between the supplied value and the atom's declared type.
Source
Thrown at tsunami/engine/atomimpl.go:67
return nil
}
// Try direct assignment if it's already type T
if typed, ok := val.(T); ok {
a.val = typed
return nil
}
// Try JSON marshaling/unmarshaling
jsonBytes, err := json.Marshal(val)
if err != nil {
var result T
return fmt.Errorf("failed to adapt type from %T => %T, input type failed to marshal: %w", val, result, err)
}
var result T
if err := json.Unmarshal(jsonBytes, &result); err != nil {
return fmt.Errorf("failed to adapt type from %T => %T: %w", val, result, err)
}
a.val = result
return nil
}
func (a *AtomImpl[T]) SetVal(val any) error {
a.lock.Lock()
defer a.lock.Unlock()
return a.setVal_nolock(val)
}
func (a *AtomImpl[T]) SetUsedBy(waveId string, used bool) {
a.lock.Lock()
defer a.lock.Unlock()
if used {
a.usedBy[waveId] = true
} else {View on GitHub (pinned to a4447c1563)
Solutions
- Pass a value of the atom's exact type T so the round-trip is trivially compatible
- Verify field names/tags and types of the value match T's JSON unmarshaling requirements
- Wrap with a type check or use the atom's dedicated typed setter if available
- Log the wrapped error's %w detail to see the exact offending field
Example fix
// before
portAtom.SetVal("8080") // atom is Atom[int]
// after
port, _ := strconv.Atoi("8080")
portAtom.SetVal(port) Defensive patterns
Strategy: type-guard
Validate before calling
if _, ok := val.(T); !ok {
b, _ := json.Marshal(val)
var probe T
if err := json.Unmarshal(b, &probe); err != nil {
return fmt.Errorf("value incompatible with atom type %T: %w", probe, err)
}
}
atom.SetVal(val) Type guard
func fitsAtomType[T any](val any) bool {
if _, ok := val.(T); ok { return true }
b, err := json.Marshal(val)
if err != nil { return false }
var probe T
return json.Unmarshal(b, &probe) == nil
} Try / catch
if err := atom.SetVal(val); err != nil {
var typeErr *json.UnmarshalTypeError
if errors.As(err, &typeErr) {
log.Printf("field %s type mismatch: %v", typeErr.Field, typeErr.Error())
}
} Prevention
- Match the value's type to the atom's generic parameter
- Update all SetVal call sites when changing T's struct shape
- Test round-trip compatibility in unit tests
When it happens
Trigger: SetVal on an atom of type T with a value whose JSON does not unmarshal into T — e.g. setting a string into an atom of int, wrong field types/missing required non-pointer fields, JSON number into a struct field of a different kind.
Common situations: Refactoring T's struct without updating callers; setting atoms from JSON-decoded generic maps; passing float/string where T expects int/bool.
Related errors
- failed to adapt type from %T => %T, input type failed to mar
- convertFileUIMessagePart expects 'file' type, got '%s'
- convertFileAIMessagePart expects 'file' type, got '%s'
- failed to unmarshal input: %w
- failed to marshal backup metadata: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/9aa81ef54f62b261.
Report an issue: GitHub.