{"record":{"id":"556753d225dc233c","repo":"gitbutlerapp/gitbutler","slug":"invalid-utf-8-in-openai-api-key","errorCode":null,"errorMessage":"Invalid UTF-8 in OPENAI_API_KEY","messagePattern":"Invalid UTF-8 in OPENAI_API_KEY","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-llm/src/openai.rs","lineNumber":106,"sourceCode":"    }\n\n    fn openai_own_key_creds() -> Result<(CredentialsKind, Sensitive<String>)> {\n        let creds = secret::retrieve(AI_OPENAI_SECRET_HANDLE, secret::Namespace::Global)?.ok_or(\n            anyhow::anyhow!(\n                \"No OpenAI own key configured. Add this through the GitButler settings\"\n            ),\n        )?;\n        Ok((CredentialsKind::OwnOpenAiKey, creds))\n    }\n\n    fn openai_env_var_creds() -> Result<(CredentialsKind, Sensitive<String>)> {\n        let creds = Sensitive(\n            std::env::var_os(\"OPENAI_API_KEY\")\n                .ok_or(anyhow::anyhow!(\n                    \"Environment variable OPENAI_API_KEY is not set\"\n                ))?\n                .into_string()\n                .map_err(|_| anyhow::anyhow!(\"Invalid UTF-8 in OPENAI_API_KEY\"))?,\n        );\n        Ok((CredentialsKind::EnvVarOpenAiKey, creds))\n    }\n}\n\nimpl OpenAIClientProvider for OpenAiProvider {\n    fn client(&self) -> Result<Client<OpenAIConfig>> {\n        match &self.credentials {\n            (CredentialsKind::EnvVarOpenAiKey, _) => {\n                let config = self.configure_custom_endpoint(OpenAIConfig::new());\n                Ok(Client::with_config(config))\n            }\n            (CredentialsKind::OwnOpenAiKey, key) => {\n                let config =\n                    self.configure_custom_endpoint(OpenAIConfig::new().with_api_key(key.0.clone()));\n                Ok(Client::with_config(config))\n            }\n","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-llm/src/openai.rs#L88-L124","documentation":"Thrown by openai_env_var_creds in crates/but-llm/src/openai.rs when OPENAI_API_KEY exists but into_string() fails because the value contains bytes that are not valid UTF-8. As with the Anthropic variant, the key must be a valid string before it can be used for API authentication, so a mangled value is rejected here.","triggerScenarios":"OPENAI_API_KEY set from binary or wrongly-encoded data (bad locale, truncated multi-byte sequence, stray control bytes); environment assembled by scripts that captured non-text output into the variable.","commonSituations":"Pasting keys through terminals with encoding mismatches; command substitution injecting extra bytes; container images with broken locale settings.","solutions":["Re-export the variable with a clean ASCII key: export OPENAI_API_KEY=\"sk-...\".","Inspect the stored bytes: printenv OPENAI_API_KEY | xxd | head.","Load the key from a UTF-8 file to avoid shell mangling."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"match std::env::var(\"OPENAI_API_KEY\") {\n    Ok(k) if !k.is_empty() => { /* proceed */ },\n    Err(std::env::VarError::NotUnicode(_)) => eprintln!(\"OPENAI_API_KEY is not valid UTF-8; re-export it\"),\n    Err(_) => eprintln!(\"OPENAI_API_KEY missing or empty\"),\n}","typeGuard":"fn openai_env_key_is_valid() -> bool {\n    matches!(std::env::var(\"OPENAI_API_KEY\"), Ok(k) if !k.is_empty() && k.is_ascii())\n}","tryCatchPattern":null,"preventionTips":["Set secrets with single quotes and plain ASCII to avoid encoding damage.","Use the CI runner's secret injection instead of echo'd shell lines.","Sanity-check env keys with printenv | xxd when installs behave oddly."],"tags":["llm","openai","environment-variables","utf-8","encoding"],"backgroundTag":"invalid-env-var-encoding","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-23T13:39:53.451Z"}