{"record":{"id":"4c22e61320a2a499","repo":"aaif-goose/goose","slug":"apikey-is-required-when-auth-is-enabled-and-no-sec","errorCode":null,"errorMessage":"apiKey is required when auth is enabled and no secret is stored","messagePattern":"apiKey is required when auth is enabled and no secret is stored","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose/src/config/declarative_providers.rs","lineNumber":246,"sourceCode":"    Ok(provider_config)\n}\n\npub fn update_custom_provider(params: UpdateCustomProviderParams) -> Result<()> {\n    let loaded_provider = load_provider(&params.id)?;\n    let existing_config = loaded_provider.config;\n    let editable = loaded_provider.is_editable;\n\n    let config = Config::global();\n    let api_key_env = if params.requires_auth {\n        let api_key_name = if existing_config.api_key_env.is_empty() {\n            generate_api_key_name(&params.id)\n        } else {\n            existing_config.api_key_env.clone()\n        };\n        if let Some(api_key) = params.api_key.as_deref() {\n            config.set_secret(&api_key_name, &api_key)?;\n        } else if config.get_secret::<String>(&api_key_name).is_err() {\n            return Err(anyhow::anyhow!(\n                \"apiKey is required when auth is enabled and no secret is stored\"\n            ));\n        }\n        api_key_name\n    } else {\n        if existing_config.api_key_env == generate_api_key_name(&params.id) {\n            config.delete_secret(&existing_config.api_key_env)?;\n        }\n        String::new()\n    };\n\n    if editable {\n        let model_infos: Vec<ModelInfo> = params\n            .models\n            .into_iter()\n            .map(|name| ModelInfo::new(name, 128000))\n            .collect();\n","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose/src/config/declarative_providers.rs#L228-L264","documentation":"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.","triggerScenarios":"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.","commonSituations":"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`.","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)"],"exampleFix":"// before\nlet params = UpdateCustomProviderParams { requires_auth: true, api_key: None, .. };\nupdate_custom_provider(params)?;\n\n// after\nlet params = UpdateCustomProviderParams {\n    requires_auth: true,\n    api_key: Some(read_api_key_from_user()),\n    ..\n};\nupdate_custom_provider(params)?;","handlingStrategy":"validation","validationCode":"use goose::config::Config;\n\n// before update_custom_provider with requires_auth and no api_key:\nif params.requires_auth && params.api_key.is_none() {\n    let key_name = if existing_config.api_key_env.is_empty() {\n        generate_api_key_name(&params.id)\n    } else {\n        existing_config.api_key_env.clone()\n    };\n    if Config::global().get_secret::<String>(&key_name).is_err() {\n        // prompt the user for the key and include it in the update params\n    }\n}","typeGuard":null,"tryCatchPattern":"match update_custom_provider(params) {\n    Err(e) if e.to_string().contains(\"apiKey is required when auth is enabled\") => {\n        // re-ask for the key, then retry the update with api_key: Some(...)\n    }\n    other => other?,\n}","preventionTips":["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"],"tags":["providers","auth","secrets","custom-providers"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}