aaif-goose/goose · error
apiKey cannot be empty
Error message
apiKey cannot be empty
What it means
create_custom_provider stores the API key as a secret named `<ID>_API_KEY` (generate_api_key_name) when requires_auth is true. Before storing, it requires a non-blank api_key (None or whitespace-only is rejected with this error) so the secret is never written empty; nothing is persisted on failure.
Source
Thrown at crates/goose/src/config/declarative_providers.rs:177
pub headers: Option<HashMap<String, String>>,
pub requires_auth: bool,
pub catalog_provider_id: Option<String>,
pub base_path: Option<String>,
pub preserves_thinking: Option<bool>,
}
pub fn create_custom_provider(
params: CreateCustomProviderParams,
) -> Result<DeclarativeProviderConfig> {
let id = generate_id(¶ms.display_name);
validate_provider_id(&id)?;
let api_key_env = if params.requires_auth {
let api_key = params
.api_key
.as_deref()
.filter(|api_key| !api_key.trim().is_empty())
.ok_or_else(|| anyhow::anyhow!("apiKey cannot be empty"))?;
let api_key_name = generate_api_key_name(&id);
let config = Config::global();
config.set_secret(&api_key_name, &api_key)?;
api_key_name
} else {
String::new()
};
let model_infos: Vec<ModelInfo> = params
.models
.into_iter()
.map(|name| ModelInfo::new(name, 128000))
.collect();
let engine = ProviderEngine::from_str(¶ms.engine)?;
let preserves_thinking = params
.preserves_thinking
.unwrap_or_else(|| should_preserve_thinking_by_default(&engine));View on GitHub (pinned to 3810898a74)
Solutions
- Supply a real api_key in the create params
- If the endpoint needs no auth (local gateways like Ollama), create the provider with requires_auth: false
Example fix
// before
let params = CreateCustomProviderParams { requires_auth: true, api_key: None, .. };
// after
let params = CreateCustomProviderParams {
requires_auth: true,
api_key: Some(std::env::var("ACME_API_KEY")?),
..
}; Defensive patterns
Strategy: validation
Validate before calling
let params = CreateCustomProviderParams { /* ... */ };
if params.requires_auth {
let key = params.api_key.as_deref().unwrap_or("").trim();
assert!(!key.is_empty(), "an API key is required for auth-enabled providers");
} Type guard
fn has_auth_inputs(params: &CreateCustomProviderParams) -> bool {
!params.requires_auth
|| params.api_key.as_deref().is_some_and(|k| !k.trim().is_empty())
} Prevention
- Collect and validate the API key in the UI before enabling requires_auth
- Trim pasted keys and reject blanks client-side
- Use requires_auth: false for local no-auth endpoints
When it happens
Trigger: Calling create_custom_provider with CreateCustomProviderParams { requires_auth: true, api_key: None } or api_key: Some(" ") — the value is filtered on trim().is_empty().
Common situations: UI or script creating an auth-required provider before the user pasted the key; passing an unset environment variable; whitespace paste from a clipboard.
Related errors
- apiKey is required when auth is enabled and no secret is sto
- missing required key {}: {}
- Required environment variable {} is not set
- Invalid provider id: provider id cannot be empty
- Invalid provider id: {}
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/055f66f9a82f35c3.
Report an issue: GitHub.