BoundaryML/baml · error · ConvertError
Recursive type alias without indirection: {0}
Error message
Recursive type alias without indirection: {0} What it means
ConvertError::DirectRecursiveTypeAlias(DefKey) is raised when a type alias directly contains a reference to itself (or chains to itself) with no indirection — e.g. `type A = B; type B = A;` or `type A = A;`. Such aliases are invalid because the recursion is not broken by a container like a list or an optional.
Source
Thrown at baml_language/crates/bex_sap/src/sap_model/convert.rs:47
FloatLiteral,
#[error("Non-parsable type: {0:?}")]
NonParsableType(Box<SapTy>),
#[error("Unknown class: {0}")]
UnknownClass(DefKey),
#[error("Unknown enum: {0}")]
UnknownEnum(DefKey),
#[error("Unknown type alias: {0}")]
UnknownTypeAlias(DefKey),
#[error("Unknown name (could not determine if it was a class, enum, or type alias): {0}")]
UnknownName(DefKey),
#[error("Could not add a type to the database as the name `{0}` is already present")]
AlreadyPresent(DefKey),
#[error("Recursion depth exceeded for {0}")]
RecursionDepthExceeded(&'static str),
#[error("Unions must be flattened")]
UnflattenedUnion,
/// Something like `type A = B; type B = A;` is invalid.
#[error("Recursive type alias without indirection: {0}")]
DirectRecursiveTypeAlias(DefKey),
#[error("Internal error (please report): {0}")]
InternalError(&'static str),
}
const MAX_RECURSION_DEPTH: usize = 16;
/// Contains stuff from [`sys_types::SysOpContext`] that we need for converting to the sap model.
///
/// ## Representation
/// - Unions should be flattened:
/// - Union members cannot be unions
/// - Union members cannot be optional
/// - Union members cannot be type aliases which themselves resolve to unions (or optionals)
/// - Same rules for the inner type of an optional type
/// - Type aliases should be flattened:
/// - Type aliases cannot directly contain the name of another type alias (or itself)
/// - example: `type A = int; type B = A;` is invalid (`B` should be updated to directly reference `int`)View on GitHub (pinned to bd85ce9dee)
Solutions
- Break the cycle by adding indirection — wrap the recursive reference in a list or optional, e.g. type A = A[] | null.
- Replace the cyclic alias pair with a class: recursive classes like class Tree { children: Tree[] } are allowed.
- Review the two alias declarations named in your sources and remove the direct cycle.
Example fix
// before
type A = B
type B = A
// after
class A { next: A? } // recursion via class with optional indirection Defensive patterns
Strategy: validation
Validate before calling
// Detect aliases that reference themselves directly
fn is_directly_recursive(defs: &HashMap<DefKey, SapTy>, key: &DefKey) -> bool {
let mut cur = key.clone();
for _ in 0..16 {
match defs.get(&cur) {
Some(SapTy::TypeAlias(next, _)) => {
if next == key { return true; }
cur = next.clone();
}
_ => return false,
}
}
false
} Try / catch
match result {
Err(ConvertError::DirectRecursiveTypeAlias(key)) => eprintln!("alias {key:?} recurses without indirection — add [] or ?"),
other => other,
} Prevention
- Break recursive types with a list or optional indirection.
- Use recursive classes (allowed) instead of recursive aliases.
- Lint alias declarations for cycles during code generation.
When it happens
Trigger: convert_ty's alias-flattening loop encounters SapTy::TypeAlias(name) whose name equals the alias currently being flattened; convert_type_alias also reports this shape as RecursionDepthExceeded for self-reference without indirection.
Common situations: Mutually recursive alias declarations (`type A = B; type B = A;`); a copy-paste typo making an alias reference itself; generated code emitting cyclic aliases.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Recursion depth exceeded for {0}
- Unknown type alias: {0}
- Non-parsable type: {0:?}
- Unknown class: {0}
- Unknown enum: {0}
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/31a3e1a2bdf4d832.
Report an issue: GitHub.