{"record":{"id":"a71dec370e43fe00","repo":"gitbutlerapp/gitbutler","slug":"environment-variable-openai-api-key-is-not-set","errorCode":null,"errorMessage":"Environment variable OPENAI_API_KEY is not set","messagePattern":"Environment variable OPENAI_API_KEY is not set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-llm/src/openai.rs","lineNumber":102,"sourceCode":"            .ok_or(anyhow::anyhow!(\n                \"No GitButler token available. Log-in to use the GitButler OpenAI provider\"\n            ))?;\n        Ok((CredentialsKind::GitButlerProxied, creds))\n    }\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 =","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-llm/src/openai.rs#L84-L120","documentation":"Thrown by OpenAiProvider::openai_env_var_creds in crates/but-llm/src/openai.rs when std::env::var_os(\"OPENAI_API_KEY\") returns None. It is the final rung of the OpenAI credential fallback (proxied token -> own key -> env var), so seeing it means no OpenAI credential source is configured anywhere.","triggerScenarios":"Requesting CredentialsKind::EnvVarOpenAiKey explicitly without the variable set; the full fallback chain exhausted with no login, no saved key, and no env var; the variable existing only in a different shell/service context.","commonSituations":"Fresh shells, containers, or CI jobs where OPENAI_API_KEY was never exported; the variable set in the desktop app's launch environment but not the CLI's; service units with a minimal environment block.","solutions":["Export OPENAI_API_KEY in the environment that runs the binary.","Or configure an own key in settings / log in to GitButler so earlier rungs succeed.","For services, add the variable to the unit's Environment= or the runner's secret configuration."],"exampleFix":"# before\n$ but ai ...\n# error: Environment variable OPENAI_API_KEY is not set\n\n# after\n$ export OPENAI_API_KEY=\"sk-...\"\n$ but ai ...","handlingStrategy":"validation","validationCode":"// Rust: check before selecting the env-var provider\nlet key_present = std::env::var_os(\"OPENAI_API_KEY\").is_some();\n\n// Shell (CI): guard the step\n// [ -n \"$OPENAI_API_KEY\" ] || { echo \"OPENAI_API_KEY missing\"; exit 1; }","typeGuard":"fn openai_env_key_available() -> bool {\n    std::env::var_os(\"OPENAI_API_KEY\")\n        .map(|v| v.to_str().map(|s| !s.is_empty()).unwrap_or(false))\n        .unwrap_or(false)\n}","tryCatchPattern":"let provider = match OpenAiProvider::with(Some(CredentialsKind::EnvVarOpenAiKey), model) {\n    Some(p) => p,\n    None => OpenAiProvider::with(None, model).expect(\"no OpenAI credentials\"),\n};","preventionTips":["Export OPENAI_API_KEY in the shell/service/CI environment that actually runs the binary.","Add fail-fast startup checks for required LLM env vars in automation scripts.","Remember the env var is the last fallback — configuring settings or login removes the dependency on it."],"tags":["llm","openai","environment-variables","credentials"],"backgroundTag":"missing-env-var","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-23T11:17:13.642Z"}