{"record":{"id":"a0c4bb831cd89463","repo":"clockworklabs/SpacetimeDB","slug":"ran-out-of-space-for-algebraictyperef-s","errorCode":null,"errorMessage":"ran out of space for `AlgebraicTypeRef`s","messagePattern":"ran out of space for `AlgebraicTypeRef`s","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/sats/src/typespace.rs","lineNumber":106,"sourceCode":"        self.types.get_mut(r.idx())\n    }\n\n    /// Inserts an `AlgebraicType` into the typespace\n    /// and returns an `AlgebraicTypeRef` that refers to the inserted `AlgebraicType`.\n    ///\n    /// This allows for self referential,\n    /// recursive or other complex types to be declared in the typespace.\n    ///\n    /// You can also use this to later change the meaning of the returned `AlgebraicTypeRef`\n    /// when you cannot provide the full definition of the type yet.\n    ///\n    /// Panics if the number of type references exceeds an `u32`.\n    pub fn add(&mut self, ty: AlgebraicType) -> AlgebraicTypeRef {\n        let index = self\n            .types\n            .len()\n            .try_into()\n            .expect(\"ran out of space for `AlgebraicTypeRef`s\");\n\n        self.types.push(ty);\n        AlgebraicTypeRef(index)\n    }\n\n    /// Returns `ty` combined with the context `self`.\n    pub const fn with_type<'a, T: ?Sized>(&'a self, ty: &'a T) -> WithTypespace<'a, T> {\n        WithTypespace::new(self, ty)\n    }\n\n    /// Returns the `AlgebraicType` that `r` resolves to in the context of the `Typespace`.\n    ///\n    /// Panics if `r` is not known by the `Typespace`.\n    ///\n    /// Note, this is not recursive.\n    /// To resolve all nested refs, call `resolve_refs()` on the result.\n    pub fn resolve(&self, r: AlgebraicTypeRef) -> WithTypespace<'_, AlgebraicType> {\n        self.with_type(&self[r])","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/sats/src/typespace.rs#L88-L124","documentation":"Panic in `Typespace::add`: SpacetimeDB's typespace indexes types with `AlgebraicTypeRef(u32)`; adding a type when the typespace already holds `u32::MAX` entries fails `try_into().expect(\"ran out of space for AlgebraicTypeRefs\")`. Reaching ~4.29 billion type definitions is essentially impossible for real modules, so this panic almost always indicates runaway recursion in type generation, not a legitimately large schema.","triggerScenarios":"Repeatedly calling `typespace.add(ty)` in a loop that never terminates — typically a recursive schema where adding type A triggers synthesis of more types forever (missing memoization/visited-set), or a codegen/deserializer loop feeding its own output back into `add`. The panic is the safety net that stops the infinite loop at 4 billion entries (long after memory pressure would usually kill the process).","commonSituations":"Self-referential type generation without cycle detection; a bug where the same types are re-added instead of deduplicated via `add_type`; fuzzers generating unbounded recursive schemas; building typespaces in a hot loop without reuse.","solutions":["Profile/inspect where `add` is called in a loop — look for recursion where a type's expansion produces new types indefinitely; add a visited/memo set (use the typespace's own dedup, e.g. an `add_type`-style API that intern's existing types).","Ensure recursive types are declared via the typespace's self-reference mechanism (add placeholder then fill) instead of expanding forever.","Reuse a single Typespace per module/conversion rather than building a new one per item in a loop.","If it genuinely fired from schema size (astronomically unlikely), split the module — but treat it as a recursion bug first."],"exampleFix":"// before: unbounded recursion adding new types forever\nfn add_all(ts: &mut Typespace, ty: &AlgebraicType) {\n    for elem in ty.children() { ts.add(elem.clone()); add_all(ts, &elem); } // no visited set\n}\n\n// after: memoize via interning so re-encountered types aren't re-added\nfn add_all(ts: &mut Typespace, ty: &AlgebraicType, seen: &mut HashSet<AlgebraicTypeRef>) {\n    let r = ts.add_type(ty); // dedup interning\n    if !seen.insert(r) { return; }\n    for elem in ty.children() { add_all(ts, &elem, seen); }\n}","handlingStrategy":"validation","validationCode":"// Cap recursion depth in your own type-walking code\nfn walk(ts: &mut Typespace, ty: &AlgebraicType, depth: usize) {\n    if depth > 1024 { panic_or_err!(\"recursive type expansion too deep\"); }\n    /* intern via ts.add_type (dedup) rather than ts.add when re-visiting */\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Intern types via the typespace's deduplicating API instead of raw `add` in loops.","Maintain a visited set when expanding recursive/self-referential schemas.","Reuse one Typespace per module; never build a fresh one per item in a hot loop."],"tags":["rust","spacetimedb","typespace","infinite-recursion","resource-exhaustion","panic"],"backgroundTag":"infinite-loop-in-codegen","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}