{"record":{"id":"f58f4aaf6481c5fc","repo":"aaif-goose/goose","slug":"missing-required-key-f58f4a","errorCode":null,"errorMessage":"missing required key {}: {}","messagePattern":"missing required key (.+?): (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/goose-providers/src/openai.rs","lineNumber":884,"sourceCode":"        None\n    };\n\n    if config.dynamic_models == Some(false) && custom_models.is_none() {\n        return Err(anyhow::anyhow!(\n            \"Provider '{}' has dynamic_models: false but no static models listed; \\\n             at least one entry in `models` is required.\",\n            config.name\n        ));\n    }\n\n    let api_key = if config.api_key_env.is_empty() {\n        None\n    } else {\n        match key_resolver.resolve_key(config.api_key_env.as_str()) {\n            Ok(key) => Some(key),\n            Err(err) => {\n                if config.requires_auth {\n                    anyhow::bail!(\"missing required key {}: {}\", config.api_key_env, err);\n                }\n                None\n            }\n        }\n    };\n\n    let normalized_base_url = ensure_url_scheme(&config.base_url);\n    let url = url::Url::parse(&normalized_base_url)\n        .map_err(|e| anyhow::anyhow!(\"Invalid base URL '{}': {}\", config.base_url, e))?;\n\n    let host = url[..url::Position::BeforePath].to_string();\n    let base_path = if let Some(ref explicit_path) = config.base_path {\n        explicit_path.trim_start_matches('/').to_string()\n    } else {\n        derive_base_path(url.path())\n    };\n\n    let timeout_secs = config.timeout_seconds.unwrap_or(DEFAULT_TIMEOUT_SECONDS);","sourceCodeStart":866,"sourceCodeEnd":902,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-providers/src/openai.rs#L866-L902","documentation":"Thrown by from_declarative_config when a provider declares an api_key_env variable and requires_auth: true, but the KeyResolver cannot resolve that environment variable. The message names the exact environment variable that is missing and the resolver's error, so the fix is to make that variable resolvable.","triggerScenarios":"A declarative provider with 'api_key_env: MY_GATEWAY_API_KEY' and 'requires_auth: true' while MY_GATEWAY_API_KEY is not set in the environment where goose runs; also when the env var name has a typo (e.g. OPENAI_APIKEY vs OPENAI_API_KEY).","commonSituations":"Forgetting to export the key in the shell/desktop service context (launchd/GUI apps do not inherit .bashrc exports), CI secrets not passed to the job, .env not loaded, or pointing api_key_env at a differently-named secret.","solutions":["Export the named variable before starting goose: export MY_GATEWAY_API_KEY=... (the message tells you the exact name)","For desktop/launchd launches, set the variable in the service environment or the goose settings env block, not just the interactive shell","Fix a typo'd api_key_env value so it matches the variable you actually set","If the endpoint truly needs no auth (local llama.cpp/Ollama-style server), set requires_auth: false so a missing key is tolerated"],"exampleFix":"# before\nexport OPENAI_APIKEY=sk-...   # typo: resolver looks up OPENAI_API_KEY\n\n# after\nexport OPENAI_API_KEY=sk-...","handlingStrategy":"validation","validationCode":"let var = &cfg.api_key_env;\nif cfg.requires_auth && !cfg.api_key_env.is_empty() && std::env::var(var).is_err() {\n    return Err(anyhow::anyhow!(\"export {var} before starting goose\"));\n}","typeGuard":null,"tryCatchPattern":"match OpenAiProviderBuilder::from_declarative_config(cfg, tls, resolver) {\n    Ok(b) => b,\n    Err(e) if e.to_string().starts_with(\"missing required key\") => {\n        eprintln!(\"auth config error: {e}\");\n        std::process::exit(2);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Never read the key value into logs; reference it by env var name only","For desktop launches, put required keys in the service environment or goose settings env block","Use requires_auth: false only for local no-auth endpoints"],"tags":["auth","environment","config","secrets"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}