BoundaryML/baml · error

request returned {status}: {resp_body}

Error message

request returned {status}:
{resp_body}

What it means

The CLI API client wraps each HTTP response in into_result: success statuses are deserialized as JSON, while any non-success status reads the body as text and returns it verbatim in an anyhow error prefixed with the status. It exists so backend error payloads (HTML or JSON error bodies) reach the CLI user directly.

Source

Thrown at engine/cli/src/api_client.rs:41

// pub struct GetOrCreateProjectResponse {
//     pub single_project: Option<Project>,
//     #[allow(dead_code)]
//     pub first_n_projects: Vec<Project>,
//     pub total_project_count: u64,
// }

trait ApiResponse {
    async fn into_result(self) -> Result<serde_json::Value>;
}

impl ApiResponse for reqwest::Response {
    async fn into_result(self) -> Result<serde_json::Value> {
        let status = self.status();
        if status.is_success() {
            Ok(self.json().await?)
        } else {
            let resp_body = self.text().await?;
            Err(anyhow::anyhow!("request returned {status}:\n{resp_body}"))
        }
    }
}

#[derive(Debug, Serialize)]
pub struct CreateProjectRequest {
    /// Example: "@boundaryml/baml"
    pub project_fqn: String,
}

#[derive(Debug, Deserialize)]
pub struct CreateProjectResponse {
    pub project: Project,
}

impl ApiClient {
    pub async fn create_project(&self, req: CreateProjectRequest) -> Result<CreateProjectResponse> {
        let resp = baml_runtime::request::create_client()?

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Read the {status} and {resp_body} in the error: the body usually contains the server's specific error message
  2. For 401, refresh or re-authenticate (re-login / fix API key)
  3. For 404, verify the project/resource identifier used in the request
  4. For 5xx, retry after a delay; check service status if persistent
  5. For 429, apply backoff before retrying

Example fix

// before
let project = client.get(url).send().await?.into_result().await?;
// after
match client.get(url).send().await?.into_result().await {
    Ok(project) => Ok(project),
    Err(e) if e.to_string().contains("401") => {
        client.reauthenticate().await?;
        client.get(url).send().await?.into_result().await
    }
    Err(e) => Err(e),
}
Defensive patterns

Strategy: try-catch

Validate before calling

if !api_token_is_set() { return Err(anyhow!("missing API token; run `baml-cli login` first")); }

Try / catch

match resp.into_result().await {
    Ok(v) => v,
    Err(e) if e.to_string().starts_with("request returned 401") => reauth_and_retry().await,
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Any API call whose response status is not 2xx — 401 unauthorized, 404 project not found, 422 validation error, 5xx server error — causes into_result to bail with the status line and raw body.

Common situations: Expired/missing auth token (401); requesting a project or resource name that doesn't exist (404); server-side bugs or maintenance windows (500/502/503); rate limiting (429).

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