BoundaryML/baml · error · JsonishError

Depth limit reached. Likely a circular reference.

Error message

Depth limit reached. Likely a circular reference.

What it means

`JsonishError::DepthLimitReached` is raised by the jsonish parser when parsing recurses past its configured depth limit. The parser imposes a maximum nesting depth to protect against runaway recursion, and exceeding it almost always indicates a circular or pathologically nested structure in the LLM output being parsed.

Source

Thrown at baml_language/crates/bex_sap/src/jsonish/mod.rs:15

//! This module implements parsing JSON-like data into a structured representation.
//!
//! The main entry point is the [`parse`] function, which takes a string and returns a [`Value`].
//! This is basically the jsonish equivalent of [`serde_json::from_str`] and [`serde_json::Value`].

mod parser;
mod value;

pub use parser::{ParseOptions, parse};
pub use value::{CompletionState, Fixes, Value};

/// Error type for jsonish parsing failures.
#[derive(Debug, thiserror::Error)]
pub enum JsonishError {
    #[error("Depth limit reached. Likely a circular reference.")]
    DepthLimitReached,
    #[error("No JSON objects found")]
    NoJsonObjectsFound,
    #[error("No markdown blocks found")]
    NoMarkdownBlocksFound,
    #[error("Mismatched brackets")]
    MismatchedBrackets,
    #[error("No collection to consume token: {0:?}")]
    NoCollectionForToken(char),
    #[error("Failed to parse JSON")]
    ParseFailed,
}

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Inspect the raw text being parsed and fix or sanitize the deeply nested/circular structure before parsing.
  2. Raise the parser depth limit via `ParseOptions` if the input legitimately requires deeper nesting.
  3. Pre-truncate or flatten overly nested input before handing it to the parser.
  4. Treat this as untrusted-input signal: validate LLM output structure before jsonish parsing.

Example fix

// before
let v = jsonish::parse(raw, &ParseOptions::default())?;
// after
let opts = ParseOptions { max_depth: 256, ..ParseOptions::default() };
let v = jsonish::parse(sanitize_deep_nesting(raw), &opts)?;
Defensive patterns

Strategy: validation

Validate before calling

fn nesting_depth(s: &str) -> usize {
    let (mut d, mut max) = (0i32, 0usize);
    for c in s.chars() { match c { '{' | '[' => { d += 1; max = max.max(d as usize); } '}' | ']' => d -= 1, _ => {} } }
    max
}
// reject before parsing: nesting_depth(raw) > max_depth

Try / catch

match jsonish::parse(&raw, &opts) {
    Ok(v) => handle(v),
    Err(JsonishError::DepthLimitReached) => log::warn!("input too deeply nested; sanitizing"),
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling `bex_sap::jsonish::parse` (with ParseOptions) on model output containing extremely deeply nested JSON, or a structure whose recursive descent exceeds the parser's depth limit.

Common situations: LLM emits deeply nested or self-referential-looking JSON; a prompt-injected payload designed to blow the parser's stack; default depth limits too low for legitimately nested data.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/fca56c0ab7f65151. Report an issue: GitHub.