BoundaryML/baml · error · RenderError
Non-regular recursive generic class '{class}' expands from '
Error message
Non-regular recursive generic class '{class}' expands from '{ancestor}' to '{instantiation}' What it means
BAML emits this error while expanding a recursive generic class into its output schema. A recursive generic is 'non-regular' if the generic parameters change shape across recursion levels — e.g. a class instantiating its own ancestor with different type arguments than the fixed point requires. The compiler refuses to expand it because the expansion would diverge or produce an infinite/unrepresentable type.
Source
Thrown at baml_language/crates/sys_ops/src/output_format.rs:17
use std::fmt::Write as _;
use ::sys_types::SapTy;
use baml_base::Literal as LiteralValue;
use indexmap::IndexMap;
use thiserror::Error;
/// Error type for output format rendering.
#[derive(Clone, Debug, Error)]
pub enum RenderError {
#[error("Enum '{0}' not found")]
EnumNotFound(String),
#[error("Class '{0}' not found")]
ClassNotFound(String),
#[error("Type '{0}' is not supported in outputs")]
UnsupportedType(String),
#[error(
"Non-regular recursive generic class '{class}' expands from '{ancestor}' to '{instantiation}'"
)]
NonRegularRecursiveGeneric {
class: String,
ancestor: String,
instantiation: String,
},
#[error(
"Output definitions '{first}' and '{second}' both render as '{rendered_name}' in the output schema"
)]
RenderedClassNameCollision {
rendered_name: String,
first: String,
second: String,
},
#[error(
"Output definitions '{first}' and '{second}' both render as '{rendered_name}' in the output schema"
)]View on GitHub (pinned to bd85ce9dee)
Solutions
- Make the recursive instantiation regular: ensure the class references its ancestor with the exact same type arguments as the original declaration
- Break the recursion by introducing a base case class or optional field so expansion terminates
- Replace the recursive generic with a concrete (non-generic) recursive type or an alias if parameterization isn't needed
Example fix
// before
class Node<T> { child Node<Node<T>> }
// after
class Node { child Node? } Defensive patterns
Strategy: validation
Validate before calling
fn is_regular_recursive(class: &ClassDef) -> bool {
class.type_params.iter().all(|tp| class.uses_ancestor_with_same_args(tp))
}
if !is_regular_recursive(&my_class) { /* fix instantiation before generating schema */ } Prevention
- Keep recursive generic instantiations identical to the declaring arguments
- Prefer concrete recursive types (e.g. Option<Self>) over re-parameterized recursion
- Test schema generation for recursive classes early
When it happens
Trigger: Declaring a BAML class that recursively references itself or an ancestor generic class with a different type instantiation than the regular fixed point; the expansion loop detects the mismatch between the ancestor's declaration and the new instantiation and raises this variant of OutputFormatError.
Common situations: Modeling recursive trees/linked lists in BAML schema with generics; typo in a type argument so the recursive instantiation doesn't match the original; attempting mutual recursion through generic parameters.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Schema inconsistency: {message}
- Recursion depth exceeded for {0}
- Recursive type alias without indirection: {0}
- baml.panics.StackOverflow
- Output definitions '{first}' and '{second}' both render as '
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/2f14602dfec088fa.
Report an issue: GitHub.