{"record":{"id":"946d05c53e607687","repo":"gitbutlerapp/gitbutler","slug":"no-gitbutler-token-available-log-in-to-use-the-gi","errorCode":null,"errorMessage":"No GitButler token available. Log-in to use the GitButler Anthropic provider","messagePattern":"No GitButler token available\\. Log-in to use the GitButler Anthropic provider","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-llm/src/anthropic.rs","lineNumber":138,"sourceCode":"            Err(e) => {\n                tracing::error!(\"Failed to retrieve Anthropic credentials: {}\", e);\n                None\n            }\n        }\n    }\n\n    pub fn client(&self) -> Result<AnthropicClient> {\n        let credentials = &self.credentials.1;\n        let kind = self.credentials.0.clone();\n        AnthropicClient::new(kind, credentials)\n    }\n\n    pub fn credentials_kind(&self) -> CredentialsKind {\n        self.credentials.0.clone()\n    }\n    fn gitbutler_proxied_creds() -> Result<(CredentialsKind, Sensitive<String>)> {\n        let creds = secret::retrieve(GITBUTLER_ACCESS_TOKEN_HANDLE, secret::Namespace::BuildKind)?\n            .ok_or(anyhow::anyhow!(\n                \"No GitButler token available. Log-in to use the GitButler Anthropic provider\"\n            ))?;\n        Ok((CredentialsKind::GitButlerProxied, creds))\n    }\n\n    fn anthropic_own_key_creds() -> Result<(CredentialsKind, Sensitive<String>)> {\n        let creds = secret::retrieve(AI_ANTHROPIC_SECRET_HANDLE, secret::Namespace::Global)?\n            .ok_or(anyhow::anyhow!(\n                \"No Anthropic own key configured. Add this through the GitButler settings\"\n            ))?;\n        Ok((CredentialsKind::OwnAnthropicKey, creds))\n    }\n\n    fn anthropic_env_var_creds() -> Result<(CredentialsKind, Sensitive<String>)> {\n        let creds = Sensitive(\n            std::env::var_os(\"ANTHROPIC_API_KEY\")\n                .ok_or(anyhow::anyhow!(\n                    \"Environment variable ANTHROPIC_API_KEY is not set\"","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-llm/src/anthropic.rs#L120-L156","documentation":"Thrown by AnthropicProvider::gitbutler_proxied_creds in crates/but-llm/src/anthropic.rs when secret::retrieve(GITBUTLER_ACCESS_TOKEN_HANDLE, Namespace::BuildKind) returns None — the app's secret store has no logged-in GitButler access token. The GitButler-proxied Anthropic provider forwards requests through GitButler's servers and requires that token.","triggerScenarios":"Constructing AnthropicProvider::with(Some(CredentialsKind::GitButlerProxied), _) without being logged in; or with preferred_creds None when neither an own key nor ANTHROPIC_API_KEY exists, so the fallback chain lands on the proxied-creds error first.","commonSituations":"Using but-llm in a CLI/TUI context where the desktop app never performed login; the stored token was cleared (logout, secret store reset, new keychain); CI environments with no GitButler session.","solutions":["Log in through the GitButler desktop app so the access token is stored in the secret store.","Or add your own Anthropic API key in GitButler settings (OwnAnthropicKey path).","Or export ANTHROPIC_API_KEY so the env-var credential path succeeds.","If calling provider code directly, pass preferred_creds = None to let the provider try own-key then env-var instead of hard-failing on proxied creds."],"exampleFix":"// before: force proxied creds, fails when not logged in\nlet provider = AnthropicProvider::with(Some(CredentialsKind::GitButlerProxied), model);\n\n// after: let the provider fall back through proxied -> own key -> env var\nlet provider = AnthropicProvider::with(None, model);","handlingStrategy":"fallback","validationCode":"// Check for a GitButler token before choosing the proxied provider\nlet has_token = but_secret::retrieve(GITBUTLER_ACCESS_TOKEN_HANDLE, but_secret::Namespace::BuildKind)\n    .ok()\n    .flatten()\n    .is_some();","typeGuard":"fn can_use_proxied_anthropic() -> bool {\n    secret::retrieve(GITBUTLER_ACCESS_TOKEN_HANDLE, secret::Namespace::BuildKind)\n        .ok()\n        .flatten()\n        .is_some()\n}","tryCatchPattern":"let provider = match AnthropicProvider::with(Some(CredentialsKind::GitButlerProxied), model) {\n    Some(p) => p,\n    None => AnthropicProvider::with(None, model) // falls through own-key / env-var\n        .expect(\"no Anthropic credentials configured\"),\n};","preventionTips":["Ensure a desktop-app login happened before using proxied providers in CLI contexts.","Pass preferred_creds = None in library code so the provider can fall back instead of hard-failing.","Surface 'log in or set ANTHROPIC_API_KEY' guidance in UX when this error appears."],"tags":["llm","anthropic","credentials","authentication","secret-store"],"backgroundTag":"missing-auth-token","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-23T11:17:13.642Z"}