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
- Inspect the wrapped debug error for the underlying coercion failure (bad JSON text vs type mismatch).
- Validate each field in `--json-args` against the parameter's declared type and enum variants.
- Test the payload parses as valid JSON (`jq .`) before dispatching.
- 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
- Match each --json-args field to its declared parameter type and enum variants
- Validate payloads with jq before dispatch
- Avoid shell quoting that mangles embedded JSON; prefer @file for complex payloads
- Keep helper `baml.json.deserialize` semantics in mind when changing param types
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
- type `{ty}` can't be passed through auto-CLI; deliver it via
- Expected integer, got {}
- Expected float, got {}
- feedback field "{key}" must be a string
- --json-args must be a JSON object, got: {json}
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/9adc3748dac1120e.
Report an issue: GitHub.