zed-industries/zed · error

Failed to connect to Mistral API: {} {}

Error message

Failed to connect to Mistral API: {} {}

What it means

Raised by Zed's Mistral provider when POSTing to {api_url}/chat/completions returns a non-success HTTP status. The response body is drained and embedded verbatim next to the status code, so authentication, quota, model, and upstream-server failures all surface through this single message.

Source

Thrown at crates/mistral/src/mistral.rs:458

                    Ok(line) => {
                        let line = line.strip_prefix("data: ")?;
                        if line == "[DONE]" {
                            None
                        } else {
                            match serde_json::from_str(line) {
                                Ok(response) => Some(Ok(response)),
                                Err(error) => Some(Err(anyhow!(error))),
                            }
                        }
                    }
                    Err(error) => Some(Err(anyhow!(error))),
                }
            })
            .boxed())
    } else {
        let mut body = String::new();
        response.body_mut().read_to_string(&mut body).await?;
        anyhow::bail!(
            "Failed to connect to Mistral API: {} {}",
            response.status(),
            body,
        );
    }
}

View on GitHub (pinned to f4178619ac)

Solutions

  1. Read the status code and body inside the message: 401/403 → fix the API key in Zed's assistant settings; 404/400 → verify the model identifier; 429 → wait or raise rate limits; 5xx → retry shortly
  2. Confirm the key works outside Zed: curl https://api.mistral.ai/v1/chat/completions with the same key and model
  3. Check corporate proxy/VPN interference if the body is an HTML error page
  4. Retry after a short backoff — transient 429/5xx responses commonly clear on their own
Defensive patterns

Strategy: try-catch

Validate before calling

async fn key_works(client: &dyn HttpClient, api_key: &str) -> bool {
    // cheap auth probe before wiring the provider
    let req = HttpRequest::get("https://api.mistral.ai/v1/models")
        .header("Authorization", format!("Bearer {}", api_key.trim()));
    matches!(client.send(req).await, Ok(resp) if resp.status().is_success())
}

Try / catch

match stream_chat_completion(request).await {
    Err(err) => {
        let msg = err.to_string();
        if msg.contains("429") || msg.contains("50") && msg.contains("Mistral API") {
            backoff.then_retry().await; // transient: rate limit / upstream
        } else if msg.contains("401") {
            prompt_for_new_api_key();
        } else {
            show_error(msg); // body text carries the provider detail
        }
    }
    Ok(stream) => stream,
}

Prevention

When it happens

Trigger: Any Mistral chat/stream completion call where the API answers 401 (bad/expired API key), 403, 404 (wrong model name in the request payload), 422, 429 (rate limit/quota), or 5xx. Note the request already carries `Authorization: Bearer <api_key>`; a missing key fails earlier.

Common situations: Expired or mistyped MISTRAL_API_KEY; quota exhausted on the Mistral plan; requesting a model the key has no access to; corporate proxies returning HTML error pages with a 502/503.

Related errors


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/76e260ea6d9cfea7. Report an issue: GitHub.