gitbutlerapp/gitbutler · error
with --key-option bring-your-own requires --api-key or…
Error message
{provider} with --key-option bring-your-own requires --api-key or --api-key-env What it means
When the AI key option is `bring-your-own` (BYOK), the CLI must obtain the secret non-interactively via --api-key or --api-key-env. `require_non_interactive_secret_if_byok` bails if BYOK was selected but no secret was resolved, interpolating the provider name into the message.
Solutions
- Add --api-key-env MY_PROVIDER_KEY to the command (preferred for scripts)
- Or add --api-key <value> if inline keys are acceptable
- Switch --key-option to a hosted/built-in option if the provider should use GitButler-managed keys instead
Example fix
// before but config ai --provider myproxy --key-option bring-your-own // after but config ai --provider myproxy --key-option bring-your-own --api-key-env MYPROXY_API_KEY
Defensive patterns
Strategy: validation
Validate before calling
function assertByokSecret({ keyOption, apiKey, apiKeyEnv, provider }) {
if (keyOption === 'bring-your-own' && !apiKey && !apiKeyEnv) {
throw new Error(`${provider} bring-your-own requires --api-key or --api-key-env`);
}
} Type guard
const isByokMissingSecret = (o) => o.keyOption === 'bring-your-own' && !o.apiKey && !o.apiKeyEnv;
Try / catch
try {
await configureAi(args);
} catch (e) {
if (/requires --api-key or --api-key-env/.test(e.message)) {
console.error('Supply the provider key via --api-key-env PROVIDER_KEY');
} else throw e;
} Prevention
- Treat BYOK as implying a key: always pair --key-option bring-your-own with a secret flag
- Store provider keys in env vars and reference them consistently
- Fall back to default key options when no custom key is available
When it happens
Trigger: Running `but config ai --provider <p> --key-option bring-your-own` without either --api-key or --api-key-env in a non-interactive context (ai_config_non_interactive path).
Common situations: Scripts configuring a custom provider endpoint but forgetting to pass the key; users assuming BYOK means 'no key needed'; automation where interactive prompting is unavailable so the secret must be supplied explicitly.
Understand the failure class
Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.
Related errors
- Enter an Anthropic API key
- Enter an OpenAI API key
- Environment variable ANTHROPIC_API_KEY is not set
- Environment variable OPENAI_API_KEY is not set
- Local AI configuration requires running inside a git…
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/2920b1fed64c7027.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but/src/command/config.rs:1682
return Ok(Some(Sensitive(value)));
}
if let Some(env_name) = api_key_env {
let value = std::env::var(&env_name)
.with_context(|| format!("Environment variable '{env_name}' is not set"))?;
return Ok(Some(Sensitive(value)));
}
Ok(None)
}
fn require_non_interactive_secret_if_byok(
key_option: AiKeyOption,
secret: Option<&Sensitive<String>>,
provider: &str,
) -> Result<()> {
if matches!(key_option, AiKeyOption::BringYourOwn) && secret.is_none() {
anyhow::bail!(
"{provider} with --key-option bring-your-own requires --api-key or --api-key-env"
);
}
Ok(())
}
fn maybe_set_secret(handle: &str, secret_value: Option<Sensitive<String>>) -> Result<()> {
if let Some(secret_value) = secret_value {
secret::persist(handle, &secret_value, secret::Namespace::Global)?;
}
Ok(())
}
fn edit_ai_git_config(
repo: Option<&gix::Repository>,
scope: AiScope,
edit: impl FnOnce(&mut gix::config::File) -> Result<()>,
) -> Result<()> {View on GitHub (pinned to 58e5313667)