aaif-goose/goose · error
apiKey is required when auth is enabled and no secret is…
Error message
apiKey is required when auth is enabled and no secret is stored
What it means
update_custom_provider reuses the existing api_key_env (or generates `<ID>_API_KEY` when empty). When requires_auth is true and the update params carry no api_key, it requires a secret to already exist under that name in Config; otherwise it errors. Conversely, when auth is disabled it deletes a previously generated key secret.
Solutions
- Pass api_key in the update params once — it is stored under api_key_env and future edits need no key
- Or store the secret manually under the existing api_key_env name (e.g. ACME_API_KEY) via the goose secret store
- If the provider genuinely needs no auth now, update with requires_auth: false (this also cleans up the generated secret)
Example fix
// before
let params = UpdateCustomProviderParams { requires_auth: true, api_key: None, .. };
update_custom_provider(params)?;
// after
let params = UpdateCustomProviderParams {
requires_auth: true,
api_key: Some(read_api_key_from_user()),
..
};
update_custom_provider(params)?; Defensive patterns
Strategy: validation
Validate before calling
use goose::config::Config;
// before update_custom_provider with requires_auth and no api_key:
if params.requires_auth && params.api_key.is_none() {
let key_name = if existing_config.api_key_env.is_empty() {
generate_api_key_name(¶ms.id)
} else {
existing_config.api_key_env.clone()
};
if Config::global().get_secret::<String>(&key_name).is_err() {
// prompt the user for the key and include it in the update params
}
} Try / catch
match update_custom_provider(params) {
Err(e) if e.to_string().contains("apiKey is required when auth is enabled") => {
// re-ask for the key, then retry the update with api_key: Some(...)
}
other => other?,
} Prevention
- Migrate the secret store together with custom provider JSONs to new machines
- Always offer re-entering the key when editing auth-required providers
- Note that disabling auth deletes the generated <ID>_API_KEY secret — re-enabling then requires the key again
When it happens
Trigger: Editing an existing auth-required provider without re-entering the key while the secret under its api_key_env is absent — e.g. the provider JSON was created by hand, the secret was deleted from goose config, or the key name drifted after an id change.
Common situations: Hand-authored provider JSON with requires_auth true but no matching secret ever stored; moving config to a new machine without migrating the secret store; secret removed via `goose configure`.
Related errors
- apiKey cannot be empty
- Invalid provider id
- Invalid provider id: provider id cannot be empty
- missing required key
- Provider not found
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/4c22e61320a2a499.
Report an issue: GitHub.
Appendix: source
Thrown at crates/goose/src/config/declarative_providers.rs:246
Ok(provider_config)
}
pub fn update_custom_provider(params: UpdateCustomProviderParams) -> Result<()> {
let loaded_provider = load_provider(¶ms.id)?;
let existing_config = loaded_provider.config;
let editable = loaded_provider.is_editable;
let config = Config::global();
let api_key_env = if params.requires_auth {
let api_key_name = if existing_config.api_key_env.is_empty() {
generate_api_key_name(¶ms.id)
} else {
existing_config.api_key_env.clone()
};
if let Some(api_key) = params.api_key.as_deref() {
config.set_secret(&api_key_name, &api_key)?;
} else if config.get_secret::<String>(&api_key_name).is_err() {
return Err(anyhow::anyhow!(
"apiKey is required when auth is enabled and no secret is stored"
));
}
api_key_name
} else {
if existing_config.api_key_env == generate_api_key_name(¶ms.id) {
config.delete_secret(&existing_config.api_key_env)?;
}
String::new()
};
if editable {
let model_infos: Vec<ModelInfo> = params
.models
.into_iter()
.map(|name| ModelInfo::new(name, 128000))
.collect();
View on GitHub (pinned to 3810898a74)