Hmbown/CodeWhale · error · anyhow::Error
Failed to list models: HTTP
Error message
Failed to list models: HTTP {status}: {error_text} What it means
list_models() issues GET {base_url}/models through the retrying HTTP client; any non-2xx status becomes this error, embedding the status code plus a sanitized, size-capped response body (credentials and provider noise stripped). It is the transport-level failure surface for model discovery.
Solutions
- Verify the API key and the environment variable name for the configured provider.
- Check the base_url path shape — OpenAI-style APIs usually require it to end in /v1.
- On 429/5xx, wait and retry; the client's retry policy already covers transient cases, so a persistent 429 means quota is exhausted.
- Read the sanitized body embedded in the message: it usually contains the provider's exact complaint.
Example fix
# before base_url = "https://api.provider.com" # GET /models -> 404 # after base_url = "https://api.provider.com/v1" # GET /v1/models -> 200
Defensive patterns
Strategy: retry
Try / catch
Parse the embedded status from the message: retry with backoff on 429/500/502/503; fail fast with a credentials message on 401/403; treat 404 as a base_url misconfiguration and stop retrying.
Prevention
- Smoke-test credentials with a manual GET /models during setup.
- Keep per-provider base_url templates in one config module.
- Cache the model list so a transient failure does not break startup.
When it happens
Trigger: 401/403 with an invalid or missing API key; 404 when base_url has the wrong path shape (missing or doubled /v1); 429 rate limiting; 5xx provider outages; a gateway that does not expose /models at all.
Common situations: Wrong API key environment variable at startup; base URL pointing at the provider root instead of the API root; expired or trial-exhausted keys; rate limits hit right after startup model fetch.
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
- Antigravity cloud-code is stream-only; blocking…
- Codewhale chat request should succeed
- Codewhale messages request should succeed
- Codewhale responses request should succeed
- err.last_error
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/09a9d14b0665b055.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/client.rs:2202
.to_string();
Ok(translated)
}
/// List available models from the provider.
pub async fn list_models(&self) -> Result<Vec<AvailableModel>> {
let url = api_url(&self.base_url, "models");
let response = self.send_with_retry(|| self.http_client.get(&url)).await?;
let status = response.status();
if !status.is_success() {
let raw_error_text = bounded_error_text(response, ERROR_BODY_MAX_BYTES).await;
let error_text = sanitize_http_error_body(
Some(self.api_provider.display_name()),
status.as_u16(),
&raw_error_text,
);
anyhow::bail!("Failed to list models: HTTP {status}: {error_text}");
}
let response_text = response
.text()
.await
.context("Failed to read models response body")?;
parse_models_response(&response_text)
.map(|models| apply_provider_model_cutline(self.api_provider, models))
}
/// The catalog provider id for this client (the `ProviderKind` slug, falling
/// back to the `ApiProvider` slug for legacy variants without a kind). This
/// is the id used as the cache scope and `CatalogOffering.provider`.
fn catalog_provider_id(&self) -> String {
self.api_provider
.kind()
.map(|kind| kind.as_str().to_string())
.unwrap_or_else(|| self.api_provider.as_str().to_string())View on GitHub (pinned to 0c42157ee5)