BoundaryML/baml · error · JsonishError

Mismatched brackets

Error message

Mismatched brackets

What it means

`JsonishError::MismatchedBrackets` indicates the parser encountered unbalanced or incorrectly paired delimiters (`{}`, `[]`) while extracting JSON from the input. It signals malformed JSON structure that the lenient jsonish extractor could not repair.

Source

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

//! 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. Check for truncation (finish_reason / max tokens) and raise limits or shorten the requested output.
  2. Inspect the raw text around the failure and repair unbalanced delimiters before parsing.
  3. Ask the model to re-emit the JSON completely with no commentary.
  4. Use a JSON-repair pass or a stricter prompt ("output must be one complete JSON value").

Example fix

// before
let v = jsonish::parse(truncated_output, &opts)?;
// after
let complete = if !is_balanced(&truncated_output) { request_completion(&truncated_output)? } else { truncated_output };
let v = jsonish::parse(&complete, &opts)?;
Defensive patterns

Strategy: validation

Validate before calling

fn is_balanced(s: &str) -> bool {
    let mut stack = Vec::new();
    for c in s.chars() {
        match c { '{' | '[' => stack.push(c), '}' => if stack.pop() != Some('{') { return false }, ']' => if stack.pop() != Some('[') { return false }, _ => {} }
    }
    stack.is_empty()
}
// reject or repair before parsing if !is_balanced(raw)

Try / catch

match jsonish::parse(&raw, &opts) {
    Ok(v) => Ok(v),
    Err(JsonishError::MismatchedBrackets) => jsonish::parse(&repair_brackets(&raw), &opts),
    Err(e) => Err(e.into()),
}

Prevention

When it happens

Trigger: Calling `bex_sap::jsonish::parse` on model output where braces/brackets are unbalanced — e.g. truncated JSON, prose interleaved with JSON fragments, or the model writing `[1, 2` without a closing bracket.

Common situations: Token-limit truncation cutting off the closing delimiters; the model mixing commentary into the JSON; prompt asking for multiple JSON snippets that get merged incorrectly.

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/7255b34d6d795b27. Report an issue: GitHub.