wavetermdev/waveterm · error
failed to adapt type from %T => %T, input type failed to mar
Error message
failed to adapt type from %T => %T, input type failed to marshal: %w
What it means
AtomImpl.SetVal adapts an arbitrary value to the atom's generic type T by JSON round-tripping (Marshal then Unmarshal). If the input value itself cannot be marshaled to JSON (channels, funcs, cyclic structures, unsupported types), setVal_nolock returns this error before any unmarshal is attempted.
Source
Thrown at tsunami/engine/atomimpl.go:62
func (a *AtomImpl[T]) setVal_nolock(val any) error {
if val == nil {
var zero T
a.val = zero
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) {View on GitHub (pinned to a4447c1563)
Solutions
- Pass only JSON-serializable values to SetVal (strip funcs/channels into separate fields)
- Add `json:"-"` tags to non-serializable struct fields
- Pre-serialize to a plain type (map[string]any or a DTO struct) before SetVal
- Consider matching the atom's type T exactly so no adaptation is needed
Example fix
// before
atom.SetVal(Config{Callback: myFunc}) // funcs not marshalable
// after
atom.SetVal(Config{Name: cfg.Name}) // JSON-safe fields only Defensive patterns
Strategy: validation
Validate before calling
func jsonSafe(v any) error {
_, err := json.Marshal(v)
return err
}
if err := jsonSafe(val); err != nil {
return fmt.Errorf("value not settable on atom: %w", err)
}
atom.SetVal(val) Type guard
func isJSONSerializable(v any) bool {
switch v.(type) {
case chan struct{}, func(), complex128:
return false
}
return jsonSafe(v) == nil
} Try / catch
if err := atom.SetVal(val); err != nil {
if strings.Contains(err.Error(), "failed to marshal") {
log.Printf("value %T is not JSON-serializable", val)
}
} Prevention
- Never store funcs/channels/cyclic data in atoms
- Tag non-serializable struct fields with `json:"-"`
- Prefer setting values of the atom's exact type T
When it happens
Trigger: Calling atom.SetVal with a value containing a func, channel, complex number, or a struct with cyclic references — json.Marshal fails immediately.
Common situations: Passing a struct with func/callback fields into an atom typed as a plain data struct; storing a map containing non-serializable values; accidentally passing a channel or io.Writer.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- failed to marshal backup metadata: %w
- failed to marshal bindings: %w
- error marshalling message to json: %w
- failed to adapt type from %T => %T: %w
- marshaling directory listing for %s: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/c3e3f1e5457f48a6.
Report an issue: GitHub.