wavetermdev/waveterm · error

atom %s: in %s: %s

Error message

atom %s: in %s: %s

What it means

makeAtomError builds a contextual error for ValidateAtomType failures. With a non-empty parentName it prefixes the message with both the atom name and the containing field path, produced while recursively validating that an atom's type is JSON-serializable (all fields marshalable, no invalid types like chan/func in the tree).

Source

Thrown at tsunami/util/util.go:148

func implementsJSON(t reflect.Type) bool {
	if t.Implements(jsonMarshalerT) || t.Implements(textMarshalerT) {
		return true
	}
	if t.Kind() != reflect.Pointer {
		pt := reflect.PointerTo(t)
		return pt.Implements(jsonMarshalerT) || pt.Implements(textMarshalerT)
	}
	return false
}

func ValidateAtomType(t reflect.Type, atomName string) error {
	seen := make(map[reflect.Type]bool)
	return validateAtomTypeRecursive(t, seen, atomName, "")
}

func makeAtomError(atomName string, parentName string, message string) error {
	if parentName != "" {
		return fmt.Errorf("atom %s: in %s: %s", atomName, parentName, message)
	}
	return fmt.Errorf("atom %s: %s", atomName, message)
}

func validateAtomTypeRecursive(t reflect.Type, seen map[reflect.Type]bool, atomName string, parentName string) error {
	if t == nil {
		return makeAtomError(atomName, parentName, "nil type")
	}

	if seen[t] {
		return nil
	}
	seen[t] = true

	// Check if type implements json.Marshaler or encoding.TextMarshaler
	if implementsJSON(t) {
		return nil
	}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Fix the type named in the 'in <parent>' part of the message: remove or replace the non-serializable field.
  2. Implement MarshalJSON (or encoding.TextMarshaler) on the offending type so validation accepts it.
  3. Wrap the field in a serializable type (e.g. store a channel identifier string instead of the channel itself).

Example fix

// before
type Atom struct { Events chan int `json:"events"` } // invalid
// after
type Atom struct { Events []int `json:"events"` }
// or: func (c ChanWrapper) MarshalJSON() ([]byte, error) { ... }
Defensive patterns

Strategy: validation

Validate before calling

func checkSerializable(v any) error {
    _, err := json.Marshal(v)
    return err
}

Try / catch

if err := util.ValidateAtomType(reflect.TypeOf(atom), "myatom"); err != nil {
    return fmt.Errorf("atom registration rejected: %w", err)
}

Prevention

When it happens

Trigger: Calling util.ValidateAtomType(reflect.TypeOf(myStruct), "myatom") where a nested field (named in parentName) has a type that fails validation — e.g. contains a chan, func, or unsafe.Pointer field without a MarshalJSON/TextMarshaler implementation.

Common situations: Adding a new field to an atom struct that holds a channel, function value, or other non-serializable type; registering a new atom type with an unsupported nested struct.

Related errors


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