BoundaryML/baml · error

Failed to parse response

Error message

Failed to parse response: {url}. Status: {status}
Body: {body} 
Error: {:?}

What it means

Thrown by the BAML runtime's tracing HTTP client after submitting a BAML log event. The POST completed (a status was received) but `serde_json::from_str::<T>` could not deserialize the response body into the expected type. The message includes the URL, HTTP status, raw body, and serde error for diagnosis.

Solutions

  1. Inspect the URL, status, and body embedded in the message to see what actually came back.
  2. Verify the BAML log/trace collector URL in configuration points at the correct JSON API endpoint, not a proxy or login page.
  3. Check network setup (VPN, corporate proxy) that may intercept the request and return HTML.
  4. Align BAML client and server versions so the response schema matches what the runtime expects.
  5. Retry once connectivity is restored; a transient 5xx text response will parse as this error.

Example fix

// before: pointing tracing at a webpage or proxy
BAML_LOG_URL=https://internal-proxy.corp.com
// after: point directly at the JSON collector endpoint
BAML_LOG_URL=https://api.baml.example.com/v1/log
Defensive patterns

Strategy: try-catch

Validate before calling

let resp_text = response.text()?;
if resp_text.trim_start().parse::<serde_json::Value>().is_err() {
    // endpoint did not return JSON; fix URL/connectivity before tracing calls
}

Type guard

fn is_json_body(body: &str) -> bool {
    serde_json::from_str::<serde_json::Value>(body).is_ok()
}

Try / catch

match result {
    Ok(v) => submit(v),
    Err(e) if e.to_string().contains("Failed to parse response") => {
        log::warn!("trace collector returned non-JSON body; skipping trace upload: {e}");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `post` in engine/baml-runtime/src/tracing/api_wrapper/mod.rs when the tracing/log collector endpoint returns a non-JSON body (HTML error page, empty body, plain text) or JSON whose shape does not match the expected generic type `T`.

Common situations: A proxy or corporate gateway intercepts the collector URL and returns an HTML auth page; the BAML server is down and returns a 502/503 text body; server and client BAML versions disagree on the response schema; the URL is misconfigured to point at a non-API endpoint.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at engine/baml-runtime/src/tracing/api_wrapper/mod.rs:157

            .json(body)
            .bearer_auth(&self.api_key)
            .build()?;

        let Ok(res) = self.client.execute(req).await else {
            return Err(anyhow::anyhow!("Failed to fetch: {url}"));
        };
        let status = res.status();
        let body = res.text().await?;

        if !status.is_success() {
            return Err(anyhow::anyhow!(
                "Failed to submit BAML log: {url}. Status: {status}\nBody: {body}"
            ));
        }

        match serde_json::from_str::<T>(&body) {
            Ok(v) => Ok(v),
            Err(e) => Err(anyhow::anyhow!(
                "Failed to parse response: {url}. Status: {status}\nBody: {body} \nError: {:?}",
                e
            )),
        }
    }
}

#[derive(Deserialize)]
struct LogResponse {
    #[allow(dead_code)]
    status: Option<String>,
    #[allow(dead_code)]
    message: Option<String>,
}

impl BoundaryAPI for CompleteAPIConfig {
    async fn check_cache(
        &self,

View on GitHub (pinned to bd85ce9dee)