{"record":{"id":"ab827c09c884bbac","repo":"wavetermdev/waveterm","slug":"atom-s-s","errorCode":null,"errorMessage":"atom %s: %s","messagePattern":"atom (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tsunami/util/util.go","lineNumber":150,"sourceCode":"\t\treturn true\n\t}\n\tif t.Kind() != reflect.Pointer {\n\t\tpt := reflect.PointerTo(t)\n\t\treturn pt.Implements(jsonMarshalerT) || pt.Implements(textMarshalerT)\n\t}\n\treturn false\n}\n\nfunc ValidateAtomType(t reflect.Type, atomName string) error {\n\tseen := make(map[reflect.Type]bool)\n\treturn validateAtomTypeRecursive(t, seen, atomName, \"\")\n}\n\nfunc makeAtomError(atomName string, parentName string, message string) error {\n\tif parentName != \"\" {\n\t\treturn fmt.Errorf(\"atom %s: in %s: %s\", atomName, parentName, message)\n\t}\n\treturn fmt.Errorf(\"atom %s: %s\", atomName, message)\n}\n\nfunc validateAtomTypeRecursive(t reflect.Type, seen map[reflect.Type]bool, atomName string, parentName string) error {\n\tif t == nil {\n\t\treturn makeAtomError(atomName, parentName, \"nil type\")\n\t}\n\n\tif seen[t] {\n\t\treturn nil\n\t}\n\tseen[t] = true\n\n\t// Check if type implements json.Marshaler or encoding.TextMarshaler\n\tif implementsJSON(t) {\n\t\treturn nil\n\t}\n\n\t// Allow time.Time explicitly","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/tsunami/util/util.go#L132-L168","documentation":"Top-level variant of makeAtomError with no parent context: the message applies to the atom type itself rather than a nested field. ValidateAtomType emits it when the atom's own type is nil or fails a top-level serialization check.","triggerScenarios":"util.ValidateAtomType(nil, \"atomname\") (nil type), or validating an atom whose top-level type is not JSON/Text-marshalable and not otherwise whitelisted (not time.Time, chan/func at the root, etc.).","commonSituations":"Registering a new atom with reflect.TypeOf on a nil-typed value (uninitialized generic or nil pointer without Elem); changing an atom's type to something non-serializable like a func.","solutions":["Pass a concrete type: use reflect.TypeOf((*T)(nil)).Elem() instead of a nil reflect.Type.","Make the atom type implement json.Marshaler or encoding.TextMarshaler.","Ensure the atom's root type is a serializable struct/map/primitive; move unsupported members behind a marshaler."],"exampleFix":"// before\nutil.ValidateAtomType(nil, \"mynote\") // atom mynote: nil type\n// after\ntyp := reflect.TypeOf((*NoteType)(nil)).Elem()\nutil.ValidateAtomType(typ, \"mynote\")","handlingStrategy":"validation","validationCode":"typ := reflect.TypeOf((*MyAtom)(nil)).Elem()\nif typ == nil {\n    return errors.New(\"atom type must be non-nil\")\n}\nif err := util.ValidateAtomType(typ, \"myatom\"); err != nil { ... }","typeGuard":null,"tryCatchPattern":"if err := util.ValidateAtomType(typ, name); err != nil {\n    if strings.HasPrefix(err.Error(), \"atom \"+name+\": nil type\") {\n        return fmt.Errorf(\"developer error: nil reflect.Type passed for atom %s\", name)\n    }\n    return err\n}","preventionTips":["Use reflect.TypeOf((*T)(nil)).Elem() rather than reflecting a possibly-nil value","Ensure atom root types are structs or other JSON-serializable kinds","Validate at init time, not at runtime, to fail fast"],"tags":["validation","serialization","reflection","go"],"backgroundTag":"atom-type-validation-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}