{"record":{"id":"ffeaacfcb439065c","repo":"gitbutlerapp/gitbutler","slug":"enter-an-anthropic-api-key","errorCode":null,"errorMessage":"Enter an Anthropic API key","messagePattern":"Enter an Anthropic API key","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-napi/src/ai.rs","lineNumber":143,"sourceCode":"    update: &AiConfigurationUpdate,\n    openai_has_key: bool,\n    anthropic_has_key: bool,\n) -> Result<()> {\n    let configuration = domain_configuration(update, DomainConfiguration::default())?;\n\n    if configuration.provider == LLMProviderKind::OpenAi\n        && configuration.openai.key_option == CredentialsKeyOption::BringYourOwn\n        && submitted_key(update.openai_api_key.clone()).is_none()\n        && !openai_has_key\n    {\n        bail!(\"Enter an OpenAI API key\")\n    }\n    if configuration.provider == LLMProviderKind::Anthropic\n        && configuration.anthropic.key_option == CredentialsKeyOption::BringYourOwn\n        && submitted_key(update.anthropic_api_key.clone()).is_none()\n        && !anthropic_has_key\n    {\n        bail!(\"Enter an Anthropic API key\")\n    }\n    Ok(())\n}\n\nfn domain_configuration(\n    update: &AiConfigurationUpdate,\n    mut configuration: DomainConfiguration,\n) -> Result<DomainConfiguration> {\n    configuration.provider = provider(&update.provider)?;\n    configuration.openai = OpenAiConfiguration {\n        key_option: key_option(\"OpenAI\", &update.openai_key_option)?,\n        model: update.openai_model.clone(),\n        custom_endpoint: update.openai_custom_endpoint.clone(),\n    };\n    configuration.anthropic = AnthropicConfiguration {\n        key_option: key_option(\"Anthropic\", &update.anthropic_key_option)?,\n        model: update.anthropic_model.clone(),\n    };","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-napi/src/ai.rs#L125-L161","documentation":"Validation in the AI configuration update flow: when the active provider is Anthropic with the 'BringYourOwn' credential option, a usable key must exist — either submitted in this update or already stored. If both are absent, `validate_update` rejects the update with this form-style message.","triggerScenarios":"An `AiConfigurationUpdate` with provider=anthropic and anthropic_key_option=bring-your-own, no non-empty `anthropic_api_key` in the payload (after trim), and no previously stored Anthropic key.","commonSituations":"Switching to Anthropic without entering a key; the UI sends the provider change before the key field is filled; a stored key was removed earlier.","solutions":["Include a non-empty (after trim) `anthropic_api_key` in the same update","If a key is already stored, make sure the update does not clear it and resend the stored-key state","Switch the credential option away from bring-your-own if no key should be supplied"],"exampleFix":"// before\nawait updateAiConfig({ provider: 'anthropic', anthropicKeyOption: 'bring-your-own' }); // bails\n\n// after: submit the key together with the option\nawait updateAiConfig({\n  provider: 'anthropic',\n  anthropicKeyOption: 'bring-your-own',\n  anthropicApiKey: keyInput.trim(), // must be non-empty\n});","handlingStrategy":"validation","validationCode":"// TypeScript: pre-validate the BYO key requirement client-side\nif (\n  update.provider === 'anthropic' &&\n  update.anthropicKeyOption === 'bring-your-own' &&\n  !(update.anthropicApiKey ?? '').trim() &&\n  !hasStoredAnthropicKey\n) {\n  showFieldError('anthropicApiKey', 'Enter an Anthropic API key');\n  return;\n}\nawait updateAiConfig(update);","typeGuard":null,"tryCatchPattern":"Catch the NAPI error whose message is 'Enter an Anthropic API key' and attach it to the key input field; keep the user on the form instead of failing silently.","preventionTips":["Disable submit until the BYO key field is non-empty when that option is selected","Track whether a key is already stored so provider switches do not clear it implicitly"],"tags":["ai","anthropic","api-key","validation","napi"],"backgroundTag":"missing-api-key","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-23T13:39:53.451Z"}