{"record":{"id":"2920b1fed64c7027","repo":"gitbutlerapp/gitbutler","slug":"provider-with-key-option-bring-your-own-requires-api-key-or","errorCode":null,"errorMessage":"{provider} with --key-option bring-your-own requires --api-key or --api-key-env","messagePattern":"(.+?) with --key-option bring-your-own requires --api-key or --api-key-env","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but/src/command/config.rs","lineNumber":1682,"sourceCode":"        return Ok(Some(Sensitive(value)));\n    }\n\n    if let Some(env_name) = api_key_env {\n        let value = std::env::var(&env_name)\n            .with_context(|| format!(\"Environment variable '{env_name}' is not set\"))?;\n        return Ok(Some(Sensitive(value)));\n    }\n\n    Ok(None)\n}\n\nfn require_non_interactive_secret_if_byok(\n    key_option: AiKeyOption,\n    secret: Option<&Sensitive<String>>,\n    provider: &str,\n) -> Result<()> {\n    if matches!(key_option, AiKeyOption::BringYourOwn) && secret.is_none() {\n        anyhow::bail!(\n            \"{provider} with --key-option bring-your-own requires --api-key or --api-key-env\"\n        );\n    }\n    Ok(())\n}\n\nfn maybe_set_secret(handle: &str, secret_value: Option<Sensitive<String>>) -> Result<()> {\n    if let Some(secret_value) = secret_value {\n        secret::persist(handle, &secret_value, secret::Namespace::Global)?;\n    }\n    Ok(())\n}\n\nfn edit_ai_git_config(\n    repo: Option<&gix::Repository>,\n    scope: AiScope,\n    edit: impl FnOnce(&mut gix::config::File) -> Result<()>,\n) -> Result<()> {","sourceCodeStart":1664,"sourceCodeEnd":1700,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but/src/command/config.rs#L1664-L1700","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\nbut config ai --provider myproxy --key-option bring-your-own\n// after\nbut config ai --provider myproxy --key-option bring-your-own --api-key-env MYPROXY_API_KEY","handlingStrategy":"validation","validationCode":"function assertByokSecret({ keyOption, apiKey, apiKeyEnv, provider }) {\n  if (keyOption === 'bring-your-own' && !apiKey && !apiKeyEnv) {\n    throw new Error(`${provider} bring-your-own requires --api-key or --api-key-env`);\n  }\n}","typeGuard":"const isByokMissingSecret = (o) => o.keyOption === 'bring-your-own' && !o.apiKey && !o.apiKeyEnv;","tryCatchPattern":"try {\n  await configureAi(args);\n} catch (e) {\n  if (/requires --api-key or --api-key-env/.test(e.message)) {\n    console.error('Supply the provider key via --api-key-env PROVIDER_KEY');\n  } else throw e;\n}","preventionTips":["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"],"tags":["cli","configuration","api-key"],"backgroundTag":"missing-api-key","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}