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

  1. Inspect `{other:?}` in the message to see which variant was returned
  2. Ensure no user code overrides or wraps the `baml.json` function so it returns a string
  3. Check engine/stdlib version alignment with baml_language (mismatch can change baml.json's return type)
  4. 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

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


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