BoundaryML/baml · error · LlmOpError

Jsonish error

Error message

Jsonish error: {0}

What it means

LlmOpError::JsonishError wraps a bex_sap::jsonish::JsonishError produced while flexibly parsing raw LLM output into a JSON-ish value. It surfaces the underlying jsonish parser's failure through the unified LlmOpError enum.

Solutions

  1. Inspect the wrapped JsonishError message for the exact syntax problem
  2. Adjust the prompt to request strict, valid JSON
  3. Update/extend the jsonish repair heuristics if the format is legitimately supported
  4. Retry the request, since LLM formatting faults are often transient

Example fix

// before
match jsonish::parse(text) { Err(e) => return Err(LlmOpError::JsonishError(e)), ... }
// after
let text = strip_markdown_fences(text);
match jsonish::parse(text) { ... }
Defensive patterns

Strategy: retry

Validate before calling

if raw.trim().is_empty() { return Err("empty response before jsonish parse".into()); }

Type guard

fn looks_like_json(s: &str) -> bool { let t = s.trim(); (t.starts_with('{') && t.ends_with('}')) || (t.starts_with('[') && t.ends_with(']')) }

Try / catch

match result {
    Err(LlmOpError::JsonishError(e)) => { log::warn!("jsonish: {e}"); strip_fences_and_retry(raw) }
    other => other,
}

Prevention

When it happens

Trigger: The jsonish parser invoked from the SAP parse entry points cannot convert the model's raw text (bad JSON syntax, unrepairable partial JSON) into a value, and the error is wrapped as JsonishError.

Common situations: Model emits JSON with trailing commas, comments, or markdown fences the repairer can't handle; empty responses; encoding issues.

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/5c6624086ebbd44e. Report an issue: GitHub.

Appendix: source

Thrown at baml_language/crates/sys_ops/src/sap.rs:61

        self.db().resolve_with_meta(self.types.stream_ty().as_ref())
    }
}

/// Errors that can occur during LLM operations. Relocated verbatim from
/// `sys_llm`; only `ParseResponseError`, `JsonishError` and `SapError` are
/// still constructible now that the SAP parse entry points are the sole users.
#[derive(Debug, thiserror::Error)]
pub enum LlmOpError {
    #[error("Expected {expected}, got {actual}")]
    TypeError {
        expected: &'static str,
        actual: String,
    },

    #[error("Parse response error: {0}")]
    ParseResponseError(String),

    #[error("Jsonish error: {0}")]
    JsonishError(::bex_sap::jsonish::JsonishError),

    #[error("SAP error: {0}")]
    SapError(::bex_sap::deserializer::coercer::ParsingError),
}

impl From<LlmOpError> for ::sys_types::VmRustFnError {
    fn from(e: LlmOpError) -> Self {
        let baml: ::sys_types::VmBamlError = match e {
            LlmOpError::TypeError { expected, actual } => {
                ::sys_types::VmBamlError::InvalidArgument {
                    message: format!("expected {expected}, got {actual}"),
                }
            }
            LlmOpError::ParseResponseError(e) => ::sys_types::VmBamlError::LlmClient { message: e },
            LlmOpError::JsonishError(e) => ::sys_types::VmBamlError::LlmClient {
                message: e.to_string(),
            },

View on GitHub (pinned to bd85ce9dee)