{"record":{"id":"31a3e1a2bdf4d832","repo":"BoundaryML/baml","slug":"recursive-type-alias-without-indirection-0","errorCode":null,"errorMessage":"Recursive type alias without indirection: {0}","messagePattern":"Recursive type alias without indirection: (.+?)","errorType":"error_code","errorClass":"ConvertError","httpStatus":null,"severity":"error","filePath":"baml_language/crates/bex_sap/src/sap_model/convert.rs","lineNumber":47,"sourceCode":"    FloatLiteral,\n    #[error(\"Non-parsable type: {0:?}\")]\n    NonParsableType(Box<SapTy>),\n    #[error(\"Unknown class: {0}\")]\n    UnknownClass(DefKey),\n    #[error(\"Unknown enum: {0}\")]\n    UnknownEnum(DefKey),\n    #[error(\"Unknown type alias: {0}\")]\n    UnknownTypeAlias(DefKey),\n    #[error(\"Unknown name (could not determine if it was a class, enum, or type alias): {0}\")]\n    UnknownName(DefKey),\n    #[error(\"Could not add a type to the database as the name `{0}` is already present\")]\n    AlreadyPresent(DefKey),\n    #[error(\"Recursion depth exceeded for {0}\")]\n    RecursionDepthExceeded(&'static str),\n    #[error(\"Unions must be flattened\")]\n    UnflattenedUnion,\n    /// Something like `type A = B; type B = A;` is invalid.\n    #[error(\"Recursive type alias without indirection: {0}\")]\n    DirectRecursiveTypeAlias(DefKey),\n    #[error(\"Internal error (please report): {0}\")]\n    InternalError(&'static str),\n}\n\nconst MAX_RECURSION_DEPTH: usize = 16;\n\n/// Contains stuff from [`sys_types::SysOpContext`] that we need for converting to the sap model.\n///\n/// ## Representation\n/// - Unions should be flattened:\n///   - Union members cannot be unions\n///   - Union members cannot be optional\n///   - Union members cannot be type aliases which themselves resolve to unions (or optionals)\n///   - Same rules for the inner type of an optional type\n/// - Type aliases should be flattened:\n///   - Type aliases cannot directly contain the name of another type alias (or itself)\n///   - example: `type A = int; type B = A;` is invalid (`B` should be updated to directly reference `int`)","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/baml_language/crates/bex_sap/src/sap_model/convert.rs#L29-L65","documentation":"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.","triggerScenarios":"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.","commonSituations":"Mutually recursive alias declarations (`type A = B; type B = A;`); a copy-paste typo making an alias reference itself; generated code emitting cyclic aliases.","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."],"exampleFix":"// before\ntype A = B\ntype B = A\n// after\nclass A { next: A? } // recursion via class with optional indirection","handlingStrategy":"validation","validationCode":"// Detect aliases that reference themselves directly\nfn is_directly_recursive(defs: &HashMap<DefKey, SapTy>, key: &DefKey) -> bool {\n    let mut cur = key.clone();\n    for _ in 0..16 {\n        match defs.get(&cur) {\n            Some(SapTy::TypeAlias(next, _)) => {\n                if next == key { return true; }\n                cur = next.clone();\n            }\n            _ => return false,\n        }\n    }\n    false\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(ConvertError::DirectRecursiveTypeAlias(key)) => eprintln!(\"alias {key:?} recurses without indirection — add [] or ?\"),\n    other => other,\n}","preventionTips":["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."],"tags":["sap","baml","type-alias","recursion","cycle"],"backgroundTag":"invalid-config-value","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}