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
- Parse the status/body from the message; 401 -> re-sign in to Copilot
- Trim conversation history / reduce payload size for 413 responses
- Switch model for 4xx model-policy rejections; verify entitlements
- 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
- Trim/summarize long conversation histories client-side before hitting size limits
- Cache the models list and only request entitled model ids
- Distinguish retryable (429/5xx) from terminal (401/403) statuses in the handler
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
- Failed to connect to API: {} {}
- The Copilot sign-in code expired. Please try again.
- could not locate run '{run_id}' in the local run index ({run
- unsupported Copilot language server architecture: {architect
- Copilot sign-in was cancelled.
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/b05204e7e76bd3cf.
Report an issue: GitHub.