gitbutlerapp/gitbutler · error
Invalid UTF-8 in OPENAI_API_KEY
Error message
Invalid UTF-8 in OPENAI_API_KEY
What it means
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.
Source
Thrown at crates/but-llm/src/openai.rs:106
}
fn openai_own_key_creds() -> Result<(CredentialsKind, Sensitive<String>)> {
let creds = secret::retrieve(AI_OPENAI_SECRET_HANDLE, secret::Namespace::Global)?.ok_or(
anyhow::anyhow!(
"No OpenAI own key configured. Add this through the GitButler settings"
),
)?;
Ok((CredentialsKind::OwnOpenAiKey, creds))
}
fn openai_env_var_creds() -> Result<(CredentialsKind, Sensitive<String>)> {
let creds = Sensitive(
std::env::var_os("OPENAI_API_KEY")
.ok_or(anyhow::anyhow!(
"Environment variable OPENAI_API_KEY is not set"
))?
.into_string()
.map_err(|_| anyhow::anyhow!("Invalid UTF-8 in OPENAI_API_KEY"))?,
);
Ok((CredentialsKind::EnvVarOpenAiKey, creds))
}
}
impl OpenAIClientProvider for OpenAiProvider {
fn client(&self) -> Result<Client<OpenAIConfig>> {
match &self.credentials {
(CredentialsKind::EnvVarOpenAiKey, _) => {
let config = self.configure_custom_endpoint(OpenAIConfig::new());
Ok(Client::with_config(config))
}
(CredentialsKind::OwnOpenAiKey, key) => {
let config =
self.configure_custom_endpoint(OpenAIConfig::new().with_api_key(key.0.clone()));
Ok(Client::with_config(config))
}
View on GitHub (pinned to caf1f223d3)
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.
Defensive patterns
Strategy: validation
Validate before calling
match std::env::var("OPENAI_API_KEY") {
Ok(k) if !k.is_empty() => { /* proceed */ },
Err(std::env::VarError::NotUnicode(_)) => eprintln!("OPENAI_API_KEY is not valid UTF-8; re-export it"),
Err(_) => eprintln!("OPENAI_API_KEY missing or empty"),
} Type guard
fn openai_env_key_is_valid() -> bool {
matches!(std::env::var("OPENAI_API_KEY"), Ok(k) if !k.is_empty() && k.is_ascii())
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Pasting keys through terminals with encoding mismatches; command substitution injecting extra bytes; container images with broken locale settings.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Invalid UTF-8 in ANTHROPIC_API_KEY
- Environment variable OPENAI_API_KEY is not set
- PR template exists but must be valid UTF-8 text or markdown
- Environment variable ANTHROPIC_API_KEY is not set
- No GitButler token available. Log-in to use the GitButler Op
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/556753d225dc233c.
Report an issue: GitHub.