BoundaryML/baml · error

baml.json.deserialize failed: {e:?}

Error message

baml.json.deserialize failed: {e:?}

What it means

Argument coercion routes every value through the engine's own `baml.json.deserialize` helper (a BAML-level function invoked with the target type as `T`). If that internal call fails - malformed JSON text, value not coercible to `T` - the error is wrapped with this message including the debug-formatted engine error.

Source

Thrown at baml_language/crates/baml_exec/src/dispatch.rs:293

}

/// Coerce JSON text into a typed BAML value via the stdlib's
/// `baml.json.deserialize<T>` (which dispatches user `from_json` overrides).
async fn deserialize_via_baml_json(
    engine: &Arc<BexEngine>,
    json_text: &str,
    ty: &RuntimeTy,
    helper_context: &HelperCallContext,
) -> Result<BexExternalValue> {
    let result = engine
        .call_function(
            "baml.json.deserialize",
            vec![BexExternalValue::String(json_text.into())],
            helper_context.call_context(indexmap::IndexMap::from([("T".to_string(), ty.clone())])),
            true,
        )
        .await
        .map_err(|e| anyhow!("baml.json.deserialize failed: {e:?}"))?;
    Ok(result)
}

#[cfg(test)]
mod tests {
    use baml_type::TyAttr;
    use bex_engine::BexEngine;
    use sys_native::SysOpsExt;

    use super::*;

    fn engine(source: &str) -> Arc<BexEngine> {
        let snapshot = baml_tests::engine::compile_source(source);
        Arc::new(
            BexEngine::new(snapshot, Arc::new(sys_native::SysOps::native()), Vec::new())
                .expect("BexEngine::new should succeed"),
        )
    }

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Inspect the wrapped debug error for the underlying coercion failure (bad JSON text vs type mismatch).
  2. Validate each field in `--json-args` against the parameter's declared type and enum variants.
  3. Test the payload parses as valid JSON (`jq .`) before dispatching.
  4. Use `--json-args @file` with a verified file to rule out shell quoting mangling the JSON.

Example fix

// before
baml run myFunc -- --json-args '{"count": "three"}'  // count: int

// after
baml run myFunc -- --json-args '{"count": 3}'
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-validate each --json-args field parses cleanly
let v: serde_json::Value = serde_json::from_str(field_text)
    .map_err(|e| format!("param {name}: invalid JSON: {e}"))?;

Try / catch

match result {
    Err(e) if e.to_string().contains("baml.json.deserialize failed") => {
        eprintln!("argument coercion failed; check JSON values against declared types: {e:?}");
    }
    other => other,
}

Prevention

When it happens

Trigger: `deserialize_via_baml_json` awaits the helper call and maps any failure to `baml.json.deserialize failed: {e:?}`; triggered by per-arg JSON text from `--json-args` that doesn't parse or doesn't match the declared parameter type.

Common situations: Passing a string where an int is expected, malformed nested JSON inside `--json-args`, or enum values that don't match declared variants during auto-CLI dispatch.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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