{"record":{"id":"e400d8aa1981b079","repo":"BoundaryML/baml","slug":"depth-limit-reached-likely-a-circular-reference-entry","errorCode":null,"errorMessage":"Depth limit reached. Likely a circular reference.","messagePattern":"Depth limit reached\\. Likely a circular reference\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/baml-lib/jsonish/src/jsonish/parser/entry.rs","lineNumber":20,"sourceCode":"use baml_types::CompletionState;\n\nuse super::ParseOptions;\nuse crate::jsonish::{\n    parser::{\n        fixing_parser,\n        markdown_parser::{self, MarkdownResult},\n        multi_json_parser,\n    },\n    value::Fixes,\n    Value,\n};\n\npub(super) fn parse_func(str: &str, mut options: ParseOptions, is_done: bool) -> Result<Value> {\n    log::debug!(\"Parsing:\\n{options:?}\\n-------\\n{str}\\n-------\");\n\n    options.depth += 1;\n    if options.depth > 100 {\n        return Err(anyhow::anyhow!(\n            \"Depth limit reached. Likely a circular reference.\"\n        ));\n    }\n\n    match serde_json::from_str(str) {\n        Ok(mut v) => {\n            match &mut v {\n                Value::String(_, completion_state) => {\n                    // The string must have been contained in quotes in order\n                    // to parse as a JSON string, therefore it is complete.\n                    *completion_state = CompletionState::Complete;\n                }\n                Value::Number(_, completion_state) => {\n                    *completion_state = CompletionState::Incomplete;\n                }\n                Value::Boolean(_) => {}\n                Value::Object(_, _) => {}\n                Value::Array(_, _) => {}","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/baml-lib/jsonish/src/jsonish/parser/entry.rs#L2-L38","documentation":"parse_func increments a depth counter on every recursive parse attempt and aborts when depth exceeds 100. This guards against pathological recursive input (e.g. deeply nested or self-referential structures) causing stack exhaustion; the message suggests the input looked like a circular reference.","triggerScenarios":"Calling jsonish parse/parse_func (directly or via from_str) with input whose repair attempts recurse more than 100 levels — extremely deeply nested arrays/objects or a fixer that repeatedly re-wraps content.","commonSituations":"LLM output containing hundreds of nested brackets (e.g. model loops generating '[[' repetition), or parser repair heuristics feeding their own output back in.","solutions":["Inspect the raw input for runaway nested brackets or repeated prefixes and truncate/clean it before parsing","Retry the LLM generation with instructions to emit flat, valid JSON","If legitimately deep input is expected, raise the depth limit in ParseOptions/entry.rs","Catch the error and fall back to a lenient extractor (e.g. markdown parser or regex extraction)"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fn nesting_depth(s: &str) -> usize {\n    let mut d = 0usize; let mut max = 0usize;\n    for c in s.chars() { match c { '{' | '[' => { d += 1; max = max.max(d); } '}' | ']' => d = d.saturating_sub(1), _ => {} } }\n    max\n}\n// reject if nesting_depth(input) > 60","typeGuard":null,"tryCatchPattern":"match parse(input) {\n    Err(e) if e.to_string().contains(\"Depth limit\") => retry_flat_generation(),\n    other => other,\n}","preventionTips":["Scan for runaway bracket repetition before parsing","Cap max output tokens to reduce loop degeneration","Instruct the model to emit flat JSON"],"tags":["json","recursion","depth-limit","parsing"],"backgroundTag":"json-parse-error","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"}