{"record":{"id":"48723306d5a19f84","repo":"gitbutlerapp/gitbutler","slug":"invalid-utf-8-in-anthropic-api-key","errorCode":null,"errorMessage":"Invalid UTF-8 in ANTHROPIC_API_KEY","messagePattern":"Invalid UTF-8 in ANTHROPIC_API_KEY","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-llm/src/anthropic.rs","lineNumber":159,"sourceCode":"        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\"\n                ))?\n                .into_string()\n                .map_err(|_| anyhow::anyhow!(\"Invalid UTF-8 in ANTHROPIC_API_KEY\"))?,\n        );\n        Ok((CredentialsKind::EnvVarAnthropicKey, creds))\n    }\n}\n\nimpl LLMClient for AnthropicProvider {\n    fn model(&self) -> Option<String> {\n        self.model.clone()\n    }\n\n    fn tool_calling_loop_stream(\n        &self,\n        system_message: &str,\n        chat_messages: Vec<ChatMessage>,\n        tool_set: &mut impl Toolset,\n        model: &str,\n        on_token: impl Fn(&str) + Send + Sync + 'static,\n    ) -> Result<(String, Vec<ChatMessage>)> {","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-llm/src/anthropic.rs#L141-L177","documentation":"Thrown by `anthropic_env_var_creds` when `ANTHROPIC_API_KEY` exists in the environment but is not valid UTF-8. The function uses `OsString::into_string()`, which fails for non-UTF-8 bytes (e.g. on Unix, arbitrary byte sequences are legal in env vars), and maps that failure to this error. The provider refuses to proceed with a malformed credential rather than sending garbage to the API.","triggerScenarios":"`std::env::var_os(\"ANTHROPIC_API_KEY\")` succeeds but the returned OsString fails `into_string()` — the variable contains invalid UTF-8 bytes, typically from a corrupted shell profile, a bad export, or binary paste into a config file.","commonSituations":"Pasting a key with a broken multi-byte character from a rich-text editor; shell profile encoding issues; a script writing the key with wrong encoding; secrets managers emitting raw bytes.","solutions":["Re-export the variable with a clean ASCII/UTF-8 value: export ANTHROPIC_API_KEY=$(cat key.txt) after verifying key.txt is UTF-8","Inspect the raw bytes (e.g. `echo -n \"$ANTHROPIC_API_KEY\" | xxd`) and remove non-ASCII characters","Re-copy the key fresh from the Anthropic console and avoid rich-text paste","Alternatively store the key via GitButler settings instead of the environment"],"exampleFix":"// before (shell, contains invalid byte)\nexport ANTHROPIC_API_KEY=$'sk-ant-\\xff...'\n\n// after\nexport ANTHROPIC_API_KEY=sk-ant-api03-clean-utf8-key","handlingStrategy":"validation","validationCode":"fn anthropic_key_is_utf8() -> bool {\n    std::env::var_os(\"ANTHROPIC_API_KEY\")\n        .map(|v| v.into_string().is_ok())\n        .unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = creds_result {\n    if e.to_string().contains(\"Invalid UTF-8\") {\n        eprintln!(\"ANTHROPIC_API_KEY contains non-UTF-8 bytes; re-copy the key\");\n    }\n}","preventionTips":["Copy keys as plain text from the provider console; avoid rich-text paste","Ensure dotfiles and provisioning scripts are saved as UTF-8","Verify with `echo -n \"$ANTHROPIC_API_KEY\" | xxd | grep -v ' 41\\| 73'` style byte checks when in doubt","Keep terminal/locale in UTF-8 (export LANG=C.UTF-8)"],"tags":["environment","encoding","utf-8","api-key"],"backgroundTag":"invalid-env-var-value","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}