BoundaryML/baml · error
Failed to parse JSON
Error message
Failed to parse JSON
What it means
parse_func tries serde_json first, then a series of fallback/fixed parsers, and if every strategy fails to produce a Value it returns a generic 'Failed to parse JSON'. It is the terminal failure of the whole jsonish parsing pipeline for the given string.
Source
Thrown at engine/baml-lib/jsonish/src/jsonish/parser/entry.rs:237
}
Err(e) => {
log::debug!("Error fixing json: {e:?}");
}
}
}
if options.allow_as_string {
return Ok(Value::String(
str.to_string(),
if is_done {
CompletionState::Complete
} else {
CompletionState::Incomplete
},
));
}
Err(anyhow::anyhow!("Failed to parse JSON"))
}
pub fn parse(str: &str, options: ParseOptions, is_done: bool) -> Result<Value> {
let res = parse_func(str, options, is_done)?;
Ok(res.simplify(is_done))
}
#[cfg(test)]
mod tests {
use baml_types::CompletionState;
use super::*;
use crate::jsonish::Value;
fn to_any_of(inner: Value, s: &str) -> Value {
Value::AnyOf(vec![inner], s.to_string())
}
View on GitHub (pinned to bd85ce9dee)
Solutions
- Log the raw input string and confirm it actually contains JSON-like content
- Check log::debug output ('Parsing: ...') to see which strategies were attempted
- Retry the generation with an explicit JSON schema/format instruction
- Add custom deserializers or use a markdown/code-fence wrapper so the content reaches the right parser
- Handle the Err branch with a user-facing retry instead of panicking
Example fix
// before
let v = jsonish::from_str(&target, llm_output)?;
// after
let v = match jsonish::from_str(&target, llm_output) {
Ok(v) => v,
Err(e) => { tracing::error!("unparseable output: {llm_output:?}"); return Err(e.into()); }
}; Defensive patterns
Strategy: try-catch
Validate before calling
fn has_json_shape(s: &str) -> bool { let t = s.trim(); t.starts_with('{') || t.starts_with('[') || t.contains("```") } Try / catch
match jsonish::from_str(&t, out) {
Ok(v) => v,
Err(e) if e.to_string() == "Failed to parse JSON" => {
tracing::warn!("no JSON in output: {out:.200}");
retry_with_format_instruction()
}
Err(e) => return Err(e.into()),
} Prevention
- Require JSON-only output in the prompt
- Check the response contains braces before parsing
- Keep a retry path with the format error fed back to the model
When it happens
Trigger: Passing a string to jsonish parse (or from_str) that neither serde_json nor any repair heuristic (fixing parser, markdown, multi-json, custom deserializers) can turn into a Value.
Common situations: LLM returned free-form prose with no JSON at all, an empty response, or output so malformed that even partial-repair strategies fail.
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.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- No JSON objects found
- Failed to parse JSON
- Depth limit reached. Likely a circular reference.
- No markdown blocks found
- Mismatched brackets
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/26f92635eb0a2a44.
Report an issue: GitHub.