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` when `OPENAI_API_KEY` is set but not valid UTF-8. `OsString::into_string()` fails for non-UTF-8 byte sequences and the function maps that failure to this error, refusing to use a malformed credential.
Solutions
- Re-export with a clean UTF-8 value from the OpenAI console
- Inspect bytes (echo -n "$OPENAI_API_KEY" | xxd) and strip non-ASCII characters
- Fix the script/profile writing the variable to write UTF-8 text
- Store the key via GitButler settings to bypass the env var
Example fix
// before (invalid byte) export OPENAI_API_KEY=$'sk-\xff...' // after export OPENAI_API_KEY=sk-proj-clean-key
Defensive patterns
Strategy: validation
Validate before calling
fn openai_key_is_utf8() -> bool {
std::env::var_os("OPENAI_API_KEY")
.map(|v| v.into_string().is_ok())
.unwrap_or(false)
} Try / catch
if let Err(e) = result {
if e.to_string().contains("Invalid UTF-8 in OPENAI_API_KEY") {
eprintln!("OPENAI_API_KEY has invalid bytes; re-copy as plain UTF-8");
}
} Prevention
- Paste keys from plain-text sources only
- Save provisioning scripts with UTF-8 encoding
- Run with a UTF-8 locale (LANG=C.UTF-8)
- Validate the value with a quick `[[ "$OPENAI_API_KEY" =~ ^[[:print:]]+$ ]]` check
When it happens
Trigger: `std::env::var_os("OPENAI_API_KEY")` succeeds but `.into_string()` errors because the value contains invalid UTF-8 bytes — corrupted export, wrong-encoding script, or binary paste into a dotfile.
Common situations: Pasting keys from editors/terminals that mangle encoding; locale misconfiguration (non-UTF-8 locale writing the var); provisioning scripts using binary tools without text mode.
Understand the failure class
Background: "is not a valid" / "Invalid ... value" environment variable errors: how libraries validate env vars and what to do when they reject yours — this error's family across 48 libraries.
- 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
- No AI credentials found. Configure in GitButler settings or…
- Repository path is not valid UTF-8
- Could not determine home directory
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/556753d225dc233c.
Report an issue: GitHub.
Appendix: 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 58e5313667)