BoundaryML/baml · warning
HTTP body is not UTF-8
Error message
HTTP body is not UTF-8: {} What it means
HttpBody::text decodes the recorded raw HTTP body bytes as UTF-8. If the bytes are not valid UTF-8 (binary content, compressed bodies, other encodings), the underlying from_utf8 error is wrapped as "HTTP body is not UTF-8: {e}". The library only exposes body text when it is valid UTF-8.
Solutions
- Use raw() to get the bytes and decode with the correct encoding (e.g. inflate gzip, convert latin-1).
- Check the Content-Encoding/Content-Type headers before calling text().
- Call json() only for bodies known to be UTF-8 JSON; otherwise use the byte-array fallback path.
Example fix
// before let s = body.text()?; // after let bytes = body.raw(); let s = String::from_utf8_lossy(bytes); // or gunzip first if Content-Encoding: gzip
Defensive patterns
Strategy: fallback
Validate before calling
let is_utf8 = std::str::from_utf8(body.raw()).is_ok();
Type guard
fn is_text_body(b: &HttpBody) -> bool { std::str::from_utf8(b.raw()).is_ok() } Try / catch
let text = match body.text() { Ok(t) => t.to_string(), Err(_) => String::from_utf8_lossy(body.raw()).into_owned() }; Prevention
- Check Content-Encoding and gunzip before decoding
- Use from_utf8_lossy for logging/inspection paths
- Don't assume provider bodies are UTF-8; keep raw bytes available
When it happens
Trigger: Calling HttpBody::text() (directly or via json()) on a body containing binary data — e.g. gzip-compressed responses, image bytes, or non-UTF-8 character sets like latin-1.
Common situations: Tracing/event inspection of LLM HTTP responses where a provider returned compressed or binary payloads; proxies returning binary error pages; responses with charset other than UTF-8.
Related errors
- Failed to convert function name to string
- Failed to convert to string
- Auth server returned
- baml.fetch_as: expected header key to be a valid HTTP…
- baml.fetch_as: expected header value to be a string, got
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/6aa571d55550b4f0.
Report an issue: GitHub.
Appendix: source
Thrown at engine/baml-lib/baml-types/src/tracing/events.rs:290
Err(_) => format!("[{} bytes]", self.raw.len()),
}
};
f.debug_struct("HTTPBody").field("raw", &preview).finish()
}
}
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()View on GitHub (pinned to bd85ce9dee)