BoundaryML/baml · error
Failed to deserialize value: {e}
Error message
Failed to deserialize value: {e} What it means
ValueExpr::resolve_serde resolves an expression to a serde_json::Value and then deserializes it into an arbitrary DeserializeOwned type T. If serde_json::from_value fails — the resolved JSON shape does not match T's structure — the error is wrapped as 'Failed to deserialize value: {e}' with the serde detail appended.
Source
Thrown at engine/baml-lib/baml-types/src/value_expr.rs:585
match self.resolve(ctx) {
Ok(ResolvedValue::Numeric(n, ..)) => Ok(n),
_ => Err(anyhow::anyhow!("Expected a numeric value")),
}
}
pub fn resolve_null(&self, ctx: &impl GetEnvVar) -> Result<()> {
match self.resolve(ctx) {
Ok(ResolvedValue::Null(..)) => Ok(()),
_ => Err(anyhow::anyhow!("Expected a null value")),
}
}
pub fn resolve_serde<T: serde::de::DeserializeOwned>(&self, ctx: &impl GetEnvVar) -> Result<T> {
let value = self.resolve(ctx)?;
let value: serde_json::Value = value.try_into()?;
match serde_json::from_value(value) {
Ok(v) => Ok(v),
Err(e) => Err(anyhow::anyhow!("Failed to deserialize value: {e}")),
}
}
/// Resolve and deserialize, with support for template_string calls.
pub fn resolve_serde_with_templates<T: serde::de::DeserializeOwned>(
&self,
ctx: &impl GetEnvVar,
template_renderer: &impl TemplateStringRenderer,
) -> Result<T> {
let value = self.resolve_with_templates(ctx, template_renderer)?;
let value: serde_json::Value = value.try_into()?;
match serde_json::from_value(value) {
Ok(v) => Ok(v),
Err(e) => Err(anyhow::anyhow!("Failed to deserialize value: {e}")),
}
}
/// Resolve the value to a [`ResolvedValue`], with support for template_string calls.View on GitHub (pinned to bd85ce9dee)
Solutions
- Read the serde detail after 'Failed to deserialize value:' — it names the exact field and expected type.
- Update the target struct T to match the resolved JSON (add #[serde(default)], Option, or rename attributes).
- Fix the config/expression so its shape matches T (correct types, no missing keys).
- Use resolve_serde_with_templates if the expression contains template_string parts that need rendering first.
- Inspect the intermediate serde_json::Value during development to see the actual shape.
Example fix
// before
#[derive(Deserialize)] struct Params { max_tokens: u32 } // value: {"max_tokens": "512"}
let p: Params = expr.resolve_serde(&ctx)?; // Failed to deserialize value: invalid type: string, expected u32
// after
// fix config: {"max_tokens": 512} (or accept strings via a custom deserializer)
let p: Params = expr.resolve_serde(&ctx)?; Defensive patterns
Strategy: try-catch
Validate before calling
let value: serde_json::Value = expr.resolve(&ctx)?.try_into()?;
serde_json::from_value::<T>(value.clone())
.map_err(|e| anyhow!("shape mismatch for {}: {e}", std::any::type_name::<T>()))?; Type guard
fn matches_shape<T: serde::de::DeserializeOwned>(v: &serde_json::Value) -> bool {
serde_json::from_value::<T>(v.clone()).is_ok()
} Try / catch
let parsed: T = expr.resolve_serde(&ctx)
.map_err(|e| anyhow::anyhow!("config deserialization failed; check field types: {e:#}"))?; Prevention
- Keep target struct field types aligned with the config JSON (u32 vs string etc.).
- Use #[serde(default)] / Option for optional fields.
- Add serde rename attributes when config keys differ from Rust field names.
- Inspect the resolved serde_json::Value during development before binding to T.
When it happens
Trigger: Calling resolve_serde::<T>() where the resolved JSON does not structurally match T: wrong field types (string where number required), missing required fields, arrays where structs expected, or null for a non-Option field.
Common situations: Deserializing LLM-provider parameters or user config into a Rust struct after renaming a struct field, changing a type from String to u64, or making an Option field required.
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
- JSON serialization error: {}
- baml.json.deserialize failed: {e:?}
- {0}
- Failed to serialize request result: {0}
- body record omitted log metadata
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/1f1dffccb409581d.
Report an issue: GitHub.