BoundaryML/baml · warning

HTTP body is not JSON

Error message

HTTP body is not JSON: {}

What it means

HttpBody::json first requires the body to be UTF-8 (via text()) and then parses it as JSON with serde_json. Either failure surfaces as "HTTP body is not JSON: {e}". It means the recorded HTTP body was not a JSON document.

Solutions

  1. Check the HTTP status and Content-Type header; only parse JSON when Content-Type is application/json.
  2. Inspect body.text() first and handle empty/HTML bodies before calling json().
  3. Handle streaming (SSE) bodies line-by-line rather than as a single JSON value.
  4. Fall back to raw()/as_serde_value byte-array representation when JSON parsing is not required.

Example fix

// before
let v = body.json()?;
// after
let v = match body.json() {
    Ok(v) => v,
    Err(e) => { log::warn!("non-JSON body: {}", body.text().unwrap_or("<binary>")); serde_json::Value::Null }
};
Defensive patterns

Strategy: type-guard

Validate before calling

let parseable = std::str::from_utf8(body.raw()).map(|s| serde_json::from_str::<serde_json::Value>(s).is_ok()).unwrap_or(false);

Type guard

fn is_json_body(b: &HttpBody) -> bool { b.text().map(|t| serde_json::from_str::<serde_json::Value>(t).is_ok()).unwrap_or(false) }

Try / catch

let v = body.json().unwrap_or(serde_json::Value::Null);

Prevention

When it happens

Trigger: Calling HttpBody::json() on bodies that are HTML error pages, plain-text messages, empty bodies, or truncated/invalid JSON from an upstream provider.

Common situations: Provider outages returning HTML 502 pages; streaming/SSE payloads inspected as one JSON document; endpoints returning form-encoded or plain-text responses.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


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

Appendix: source

Thrown at engine/baml-lib/baml-types/src/tracing/events.rs:295

    }
}

impl HTTPBody {
    pub fn new(body: Vec<u8>) -> Self {
        Self { raw: body }
    }

    pub fn raw(&self) -> &[u8] {
        &self.raw
    }

    pub fn text(&self) -> anyhow::Result<&str> {
        std::str::from_utf8(&self.raw).map_err(|e| anyhow::anyhow!("HTTP body is not UTF-8: {}", e))
    }

    pub fn json(&self) -> anyhow::Result<serde_json::Value> {
        serde_json::from_str(self.text()?)
            .map_err(|e| anyhow::anyhow!("HTTP body is not JSON: {}", e))
    }

    /// Returns the HTTP body as a [`serde_json::Value`].
    ///
    /// If the body is not UTF-8 or JSON, it is returned as an array of bytes.
    /// Used as input for [`serde_json::to_string_pretty`].
    pub fn as_serde_value(&self) -> serde_json::Value {
        self.json()
            .or_else(|_e| self.text().map(|s| serde_json::Value::String(s.into())))
            .unwrap_or_else(|_e| {
                serde_json::Value::Array(
                    self.raw()
                        .iter()
                        .map(|byte| serde_json::Value::from(*byte))
                        .collect(),
                )
            })
    }

View on GitHub (pinned to bd85ce9dee)