{"record":{"id":"c95ef6f51b1a1e18","repo":"tonhowtf/omniget","slug":"anthropic","errorCode":null,"errorMessage":"Anthropic: {}","messagePattern":"Anthropic: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/ai_keys.rs","lineNumber":331,"sourceCode":"/// Site do painel (New API): base sem o `/v1`.\nfn site_of(base: &str) -> String {\n    base.trim_end_matches('/')\n        .trim_end_matches(\"/v1\")\n        .to_string()\n}\n\n/// GET /models (ou equivalente) → ids dos modelos.\npub async fn models(entry: &KeyEntry) -> anyhow::Result<Vec<String>> {\n    let c = client()?;\n    let json: serde_json::Value = match entry.kind.as_str() {\n        \"anthropic\" => {\n            c.get(format!(\"{}/models?limit=1000\", entry.base_url))\n                .header(\"x-api-key\", &entry.key)\n                .header(\"anthropic-version\", \"2023-06-01\")\n                .send()\n                .await?\n                .error_for_status()\n                .map_err(|e| anyhow!(\"Anthropic: {}\", e))?\n                .json()\n                .await?\n        }\n        \"gemini\" => {\n            c.get(format!(\n                \"{}/models?pageSize=1000&key={}\",\n                entry.base_url, entry.key\n            ))\n            .send()\n            .await?\n            .error_for_status()\n            .map_err(|e| anyhow!(\"Gemini: {}\", e))?\n            .json()\n            .await?\n        }\n        _ => {\n            let mut req = c.get(format!(\"{}/models\", entry.base_url));\n            if !entry.key.is_empty() {","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/ai_keys.rs#L313-L349","documentation":"In the models() function's \"anthropic\" branch, the HTTP response is checked with error_for_status() and any non-success status is wrapped as \"Anthropic: {}\". It means the Anthropic API (at entry.base_url) rejected the GET /models request with an HTTP error — most commonly invalid x-api-key or a wrong base_url.","triggerScenarios":"Calling models/test for an anthropic entry when the stored key is revoked or mistyped, the base_url is wrong (e.g. missing or extra /v1), or the account is rate-limited/overloaded (429/529).","commonSituations":"User pasted a key from a different provider; custom proxy base_url that doesn't mirror the Anthropic API shape; expired/rotated key; network proxy returning 4xx/5xx.","solutions":["Read the wrapped status/body and fix credentials: re-enter a valid Anthropic x-api-key","Check entry.base_url — it should be the API root (e.g. https://api.anthropic.com/v1) matching the {base}/models call","Retry on 429/5xx after a delay (respect retry-after)","Use the test action to validate the key before listing models"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// pre-flight before models():\nlet resp = client.head(format!(\"{}/models\", entry.base_url)).header(\"x-api-key\", &entry.key).send().await?;\nif !resp.status().is_success() { bail!(\"Anthropic key/base_url invalido: {}\", resp.status()); }","typeGuard":null,"tryCatchPattern":"match models(entry).await {\n    Err(e) if e.to_string().starts_with(\"Anthropic:\") => {\n        if e.to_string().contains(\"429\") { schedule_retry(); } else { prompt_reenter_key(); }\n    }\n    other => handle(other),\n}","preventionTips":["Validate the key with a cheap request before saving it","Normalize base_url to the Anthropic API root (no trailing/missing /v1 surprises)","Handle 429/529 with backoff instead of failing the whole flow"],"tags":["http","api","anthropic","authentication"],"backgroundTag":"http-error-response","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}