BoundaryML/baml · error
baml.json.serialize returned non-string value: {other:?}
Error message
baml.json.serialize returned non-string value: {other:?} What it means
serialize_via_baml_json expects the `baml.json` function to return a BexExternalValue::String (the JSON text). If the call succeeds but yields any other external value variant, this error is raised. It is an internal contract violation: baml.json must produce a string representation, so a non-string result means the runtime returned something unexpected.
Source
Thrown at baml_language/crates/baml_exec/src/output.rs:112
value: BexExternalValue,
return_type: &RuntimeTy,
helper_context: &HelperCallContext,
) -> Result<String> {
let result = engine
.call_function(
"baml.json.serialize",
vec![value],
helper_context.call_context(indexmap::IndexMap::from([(
"T".to_string(),
return_type.clone(),
)])),
true,
)
.await
.map_err(|e| anyhow!("baml.json.serialize failed: {e:?}"))?;
match result {
BexExternalValue::String(s) => Ok(s.to_string()),
other => Err(anyhow!(
"baml.json.serialize returned non-string value: {other:?}"
)),
}
}
/// Human-readable formatting for `BexExternalValue`.
///
/// Thin wrapper over [`BexExternalValue::render_readable`] — the canonical
/// structural renderer, shared with the engine's uncaught-throw rendering so
/// `baml run` output and a leaked `throw` render identically.
pub fn format_value(value: &BexExternalValue) -> String {
value.render_readable()
}
View on GitHub (pinned to bd85ce9dee)
Solutions
- Inspect `{other:?}` in the message to see which variant was returned
- Ensure no user code overrides or wraps the `baml.json` function so it returns a string
- Check engine/stdlib version alignment with baml_language (mismatch can change baml.json's return type)
- File/fix an internal invariant issue in the runtime if stock baml.json returns non-string values
Example fix
// before
other => Err(anyhow!("baml.json.serialize returned non-string value: {other:?}"))
// after
other => Err(anyhow!("baml.json.serialize returned non-string value: {other:?}"))
// caller side: assert the function's return type is string before serializing Defensive patterns
Strategy: type-guard
Validate before calling
// ensure no user-defined override of baml.json and that engine/stdlib versions match assert_engine_matches_baml_language_version();
Type guard
fn is_string_value(v: &BexExternalValue) -> bool {
matches!(v, BexExternalValue::String(_))
} Try / catch
match serialize_via_baml_json(...).await {
Ok(s) => Ok(s),
Err(e) if e.to_string().contains("non-string value") => {
// log variant and treat as internal invariant violation
Err(e.context("baml.json returned non-string; check engine/stdlib versions"))
}
Err(e) => Err(e),
} Prevention
- Never override or wrap the built-in baml.json function so it returns non-string values
- Keep runtime engine and stdlib versions in lockstep with baml_language
- Add a regression test asserting baml.json returns a string for your output types
When it happens
Trigger: baml.json evaluation completes successfully but the runtime returns a non-string BexExternalValue (e.g. an object/array/number variant) instead of the serialized JSON string.
Common situations: Runtime engine version where baml.json returns a structured value rather than a string; custom or overridden `baml.json` function returning a non-string; engine/stdlib mismatch after upgrading baml_language.
Related errors
- baml.json.serialize failed: {e:?}
- endsWith() method only available on strings at {:?}
- split() method only available on strings at {:?}
- substring() method only available on strings at {:?}
- replace() method only available on strings at {:?}
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/da97f6933f9659c9.
Report an issue: GitHub.