BoundaryML/baml · error · ExposedError::ClientHttpError

LLM client "{client_name}" failed with status code: {status_

Error message

LLM client "{client_name}" failed with status code: {status_code}\nMessage: {message}

What it means

For any LLMFailure whose error code is neither Timeout nor Other(2), the orchestrator wraps the failure into ExposedError::ClientHttpError, exposing the client name, HTTP status code, detailed message, and the raw response body. This is BAML's standard way of propagating an HTTP error response from the model provider (4xx/5xx) to the caller.

Source

Thrown at engine/baml-runtime/src/internal/llm_client/orchestrator/call.rs:148

                        message,
                        raw_response,
                        ..
                    }) => {
                        match code {
                            // Timeout error
                            crate::internal::llm_client::ErrorCode::Timeout => {
                                Some(Err(anyhow::anyhow!(
                                    crate::errors::ExposedError::TimeoutError {
                                        client_name: client.clone(),
                                        message: message.clone(),
                                    }
                                )))
                            }
                            // This is some internal BAML error, so handle it like any other error
                            crate::internal::llm_client::ErrorCode::Other(2) => {
                                Some(Err(anyhow::anyhow!(message.clone())))
                            }
                            _ => Some(Err(anyhow::anyhow!(
                                crate::errors::ExposedError::ClientHttpError {
                                    client_name: client.clone(),
                                    message: message.clone(),
                                    status_code: code.clone(),
                                    detailed_message: message.clone(),
                                    raw_response: raw_response.clone(),
                                }
                            ))),
                        }
                    }
                    _ => None,
                };

                let sleep_duration = node.error_sleep_duration().cloned();
                let result = (node.scope, response, parsed_response);

                // Return None to signal success and break
                if matches!(result.1, LLMResponse::Success(_)) {

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Check status_code in the error: 401/403 -> fix API key/permissions; 429 -> backoff and reduce concurrency; 404/400 -> fix model name and options.
  2. Inspect detailed_message/raw_response for the provider's own error body explaining the rejection.
  3. Verify the api_key env var value and that the account has access to the requested model.
  4. Add a retry_policy with exponential backoff and a fallback client in the BAML function's retry strategy.
  5. Pin/adjust request options to what the provider version supports.

Example fix

// before (clients.baml)
function Extract(input: string) -> Output {
  provider "gpt4"
}
// after - add retry + fallback for HTTP failures
function Extract(input: string) -> Output {
  provider "gpt4"
  retry_policy RateLimitRetry
}
retry_policy RateLimitRetry {
  max_retries 5
  strategy { type exponential_backoff }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: verify key present and model reachable
import os
if not os.environ.get("OPENAI_API_KEY"):
    raise RuntimeError("OPENAI_API_KEY missing; would get 401 ClientHttpError")

Try / catch

// python
from baml_py import BamlError, ClientHttpError
try:
    result = b.ExtractDocs(text)
except ClientHttpError as e:
    code = e.status_code
    if code == 429:
        time.sleep(backoff); retry()
    elif code in (401, 403):
        alert("bad credentials")
    else:
        log.error("provider http %s: %s", code, e.raw_response)

Prevention

When it happens

Trigger: Calling a BAML function where the provider responds with a non-success HTTP status: 401/403 (bad key), 404 (bad model name), 429 (rate limit), 500 (provider outage), or a 400 (malformed request/parameters).

Common situations: Expired or wrong API key, model name not available on the account/region, exceeding rate limits or quota, invalid request options (temperature type errors, bad json_schema), provider-side incidents.

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/977737e5c97022ac. Report an issue: GitHub.