{"record":{"id":"09a9d14b0665b055","repo":"Hmbown/CodeWhale","slug":"failed-to-list-models-http-status-error-text","errorCode":null,"errorMessage":"Failed to list models: HTTP {status}: {error_text}","messagePattern":"Failed to list models: HTTP (.+?): (.+?)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/client.rs","lineNumber":2202,"sourceCode":"            .to_string();\n\n        Ok(translated)\n    }\n\n    /// List available models from the provider.\n    pub async fn list_models(&self) -> Result<Vec<AvailableModel>> {\n        let url = api_url(&self.base_url, \"models\");\n        let response = self.send_with_retry(|| self.http_client.get(&url)).await?;\n\n        let status = response.status();\n        if !status.is_success() {\n            let raw_error_text = bounded_error_text(response, ERROR_BODY_MAX_BYTES).await;\n            let error_text = sanitize_http_error_body(\n                Some(self.api_provider.display_name()),\n                status.as_u16(),\n                &raw_error_text,\n            );\n            anyhow::bail!(\"Failed to list models: HTTP {status}: {error_text}\");\n        }\n        let response_text = response\n            .text()\n            .await\n            .context(\"Failed to read models response body\")?;\n\n        parse_models_response(&response_text)\n            .map(|models| apply_provider_model_cutline(self.api_provider, models))\n    }\n\n    /// The catalog provider id for this client (the `ProviderKind` slug, falling\n    /// back to the `ApiProvider` slug for legacy variants without a kind). This\n    /// is the id used as the cache scope and `CatalogOffering.provider`.\n    fn catalog_provider_id(&self) -> String {\n        self.api_provider\n            .kind()\n            .map(|kind| kind.as_str().to_string())\n            .unwrap_or_else(|| self.api_provider.as_str().to_string())","sourceCodeStart":2184,"sourceCodeEnd":2220,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/client.rs#L2184-L2220","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nbase_url = \"https://api.provider.com\"    # GET /models -> 404\n\n# after\nbase_url = \"https://api.provider.com/v1\"  # GET /v1/models -> 200","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"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.","preventionTips":["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."],"tags":["rust","http","llm","api-key","rate-limit"],"backgroundTag":"http-error-response","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}