{"record":{"id":"b4b5dae408ebd752","repo":"clockworklabs/SpacetimeDB","slug":"recursive-types-not-supported","errorCode":null,"errorMessage":"recursive types not supported","messagePattern":"recursive types not supported","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/lib/src/lib.rs","lineNumber":341,"sourceCode":"    } else {\n        hex\n    };\n    hex::FromHex::from_hex(hex)\n}\n\n/// Returns a resolved `AlgebraicType` (containing no `AlgebraicTypeRefs`) for a given `SpacetimeType`,\n/// using the v9 moduledef infrastructure.\n/// Panics if the type is recursive.\n///\n/// TODO: we could implement something like this in `sats` itself, but would need a lightweight `TypespaceBuilder` implementation there.\npub fn resolved_type_via_v9<T: SpacetimeType>() -> AlgebraicType {\n    let mut builder = RawModuleDefV9Builder::new();\n    let ty = T::make_type(&mut builder);\n    let module = builder.finish();\n\n    WithTypespace::new(&module.typespace, &ty)\n        .resolve_refs()\n        .expect(\"recursive types not supported\")\n}\n","sourceCodeStart":323,"sourceCodeEnd":343,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/lib/src/lib.rs#L323-L343","documentation":"`resolved_type_via_v9<T>()` builds a raw module-def for T and resolves all type references; `resolve_refs` fails (triggering this expect) when the typespace still contains unresolvable refs, which is exactly what recursive types produce — a ref cycle can never be inlined into a single AlgebraicType. SpacetimeDB's type system does not support recursive schema types, so this is a hard error by design.","triggerScenarios":"Calling `resolved_type_via_v9` (or APIs that derive schema from a type) with T that transitively contains itself: `struct Node { next: Option<Box<Node>> }`, mutually recursive structs/enums, or any type whose expansion does not terminate.","commonSituations":"Porting linked-list/tree types from general Rust into SpacetimeDB modules; reusing recursive serde types as table rows, reducer args, or return values; tooling that inspects arbitrary user-supplied types.","solutions":["Break the cycle: model self-reference through table rows and row ids instead of nested types.","Flatten the structure: store nodes in a table (id, value, parent_id) or use an explicit arena (Vec<Node> + usize links) for internal logic.","Keep recursive types out of SpacetimeType definitions entirely; use them only in module-internal, non-schema code."],"exampleFix":"// before: recursive type — resolve_refs can never finish\n#[derive(spacetimedb::SpacetimeType)]\nstruct Node { value: u64, next: Option<Box<Node>> }\n\n// after: normalize via a table keyed by id\n#[derive(spacetimedb::SpacetimeType)]\nstruct Node { id: u64, value: u64, parent: Option<u64> } // rows in table `node`","handlingStrategy":"validation","validationCode":"// CI test: any type passed to resolved_type_via_v9 must resolve\n#[test]\nfn schema_resolves() { let _ = resolved_type_via_v9::<MyType>(); }","typeGuard":"trait NonRecursiveType: spacetimedb::SpacetimeType {} // marker implemented only for types covered by the resolving test","tryCatchPattern":null,"preventionTips":["Never nest a type inside itself (even via Box/Option) in SpacetimeType definitions.","Model graphs with tables plus row ids instead of nested recursive structures.","Run a schema-construction test for every public module type in CI."],"tags":["rust","spacetimedb","schema","recursive-type","algebraic-type"],"backgroundTag":"recursive-type-not-supported","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}