BoundaryML/baml · error · ApiError

HTTP error: {status} {body}

Error message

HTTP error: {status} {body}

What it means

This is the Display message of ApiError::Http in the BAML trace publisher. It is thrown when the trace/collector HTTP API returned a response but with an error status code; the message carries the reqwest::StatusCode and the response body for diagnosis. The library throws it so the actual server-side rejection (auth, quota, bad payload) is surfaced with its body.

Source

Thrown at engine/baml-runtime/src/tracingv2/publisher/publisher.rs:194

            }

            // D) happy path: 2xx → attempt to parse into T
            serde_json::from_slice::<TEndpoint::Response<'resp>>(&bytes)
                .map_err(ApiError::Deserialize)
        };

        match timeout(timeout_duration, fut).await {
            Ok(res) => res,
            Err(_) => Err(ApiError::Timeout(timeout_duration)),
        }
    }
}

#[derive(thiserror::Error, Debug)]
pub enum ApiError {
    #[error("Transport error: {0}")]
    Transport(reqwest::Error),
    #[error("HTTP error: {status} {body}")]
    Http {
        status: reqwest::StatusCode,
        body: String,
    },
    #[error("Failed to deserialize response: {0}")]
    Deserialize(serde_json::Error),
    #[error("Request timed out after {0:?}")]
    Timeout(Duration),
}

impl TypeLookup for RuntimeAST {
    fn type_lookup(&self, name: &str) -> Option<Arc<baml_rpc::BamlTypeId>> {
        self.ast.type_lookup(name)
    }

    fn function_lookup(&self, name: &str) -> Option<Arc<baml_rpc::ast::tops::BamlFunctionId>> {
        self.ast.function_lookup(name)
    }

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Read the status and body embedded in the error to identify the server-side cause.
  2. Check that BAML_SECRET is valid and has access to the project (re-generate the key).
  3. Back off and retry on 429/5xx responses.
  4. Check BAML cloud service status if 5xx persists.

Example fix

// before
match res.status() {
    StatusCode::OK => parse(res),
    _ => panic!("upload failed"),
}
// after
let status = res.status();
let body = res.text().await?;
if !status.is_success() {
    return Err(ApiError::Http { status, body });
}
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight key check
res = requests.get(f"{BAML_URL}/health", headers={"Authorization": f"Bearer {BAML_SECRET}"})
assert res.status_code in (200, 404), f"collector returned {res.status_code}: {res.text[:200]}"

Type guard

fn is_http_err(e: &ApiError) -> Option<(reqwest::StatusCode, &str)> {
    if let ApiError::Http { status, body } = e { Some((*status, body)) } else { None }
}

Try / catch

match publisher.publish(ev) {
    Err(ApiError::Http { status, body }) if status == reqwest::StatusCode::UNAUTHORIZED => {
        rotate_api_key();
    }
    Err(ApiError::Http { status, .. }) if status.is_server_error() || status == reqwest::StatusCode::TOO_MANY_REQUESTS => {
        backoff_and_retry();
    }
    Err(e) => log::error!("publish failed: {e}"),
    Ok(_) => {}
}

Prevention

When it happens

Trigger: The BAML collector endpoint returned a 4xx/5xx response to a trace publish or baml-src upload request: invalid or expired BAML_SECRET (401/403), rate limiting (429), server error (500), or malformed payload rejected by the API (400).

Common situations: Expired or wrong API key in BAML_SECRET, organization/project misconfiguration on the BAML dashboard, hitting rate limits with high trace volume, or the cloud service having an outage (5xx).

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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