zed-industries/zed · error

Failed to connect to API: {} {}

Error message

Failed to connect to API: {} {}

What it means

Non-2xx guard in the Copilot 'responses' API client (responses.rs): the POST carrying the Responses-style request (with Copilot-Vision-Request header for image input) failed at the HTTP layer, and the bail embeds status plus full body text. Everything before the check succeeded - serialization, headers, body send - so the failure is server-side policy/auth/capacity, not request construction.

Source

Thrown at crates/copilot_chat/src/responses.rs:319

    let request_builder = copilot_request_headers(
        HttpRequest::builder().method(Method::POST).uri(&api_url),
        &oauth_token,
        Some(is_user_initiated),
        Some(location),
    )
    .when(is_vision_request, |builder| {
        builder.header("Copilot-Vision-Request", "true")
    });

    let is_streaming = request.stream;
    let json = serde_json::to_string(&request)?;
    let request = request_builder.body(AsyncBody::from(json))?;
    let mut response = client.send(request).await?;

    if !response.status().is_success() {
        let mut body = String::new();
        response.body_mut().read_to_string(&mut body).await?;
        anyhow::bail!("Failed to connect to API: {} {}", response.status(), body);
    }

    if is_streaming {
        let reader = BufReader::new(response.into_body());
        Ok(reader
            .lines()
            .filter_map(|line| async move {
                match line {
                    Ok(line) => {
                        let line = line.strip_prefix("data: ")?;
                        if line.starts_with("[DONE]") || line.is_empty() {
                            return None;
                        }

                        match serde_json::from_str::<StreamEvent>(line) {
                            Ok(event) => Some(Ok(event)),
                            Err(error) => {
                                log::error!(

View on GitHub (pinned to f4178619ac)

Solutions

  1. Parse the status/body from the message; 401 -> re-sign in to Copilot
  2. Trim conversation history / reduce payload size for 413 responses
  3. Switch model for 4xx model-policy rejections; verify entitlements
  4. Retry with backoff on 429/5xx
Defensive patterns

Strategy: retry

Validate before calling

// Keep payloads bounded to avoid 413 before sending
if json.len() > MAX_REQUEST_BYTES {
    request.messages.truncate_to_budget(MAX_REQUEST_BYTES);
}

Try / catch

match send_responses_request(/* .. */).await {
    Ok(resp) => { /* handle */ }
    Err(err) => {
        let msg = format!("{err:#}");
        if msg.contains("401") { /* re-auth */ }
        else if msg.contains("413") { /* trim history and retry */ }
        else if msg.contains("429") || msg.contains("50") { /* backoff retry */ }
        else { return Err(err); }
    }
}

Prevention

When it happens

Trigger: Calling the Copilot responses endpoint with an expired OAuth token (401), non-entitled account or disabled model (403), rate limit (429), oversized conversation payload (413), or a vision request sent without vision entitlement (Copilot-Vision-Request: true on a non-vision account).

Common situations: Long agent conversations growing past request-size limits; model deprecation server-side; token expiry mid-session; enterprise Copilot policies disabling specific models.

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 zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/b05204e7e76bd3cf. Report an issue: GitHub.