Hmbown/CodeWhale · error
vendor is only supported by providers.openrouter
Error message
vendor is only supported by providers.openrouter
What it means
The `vendor` credential/endpoint qualifier is defined only for OpenRouter. The resolver reads `vendor` from the provider entry, validates it via `codewhale_config::validate_openrouter_vendor`, and if a vendor value is present for any provider other than `ApiProvider::Openrouter`, config loading fails. Other providers have no vendor concept, so a non-empty vendor there is always a misconfiguration.
Solutions
- Remove the `vendor` key from the non-OpenRouter provider entry in your config.
- If you meant to use a vendor-qualified OpenRouter route, move the `vendor` setting under `providers.openrouter`.
- If you are on OpenRouter and still see this, check that `api_provider` / the active route actually selects `openrouter` — the check compares against `ApiProvider::Openrouter`.
Example fix
// before (config.toml) [providers.anthropic] vendor = "bedrock" // after [providers.anthropic] # vendor removed; it is only valid under providers.openrouter
Defensive patterns
Strategy: validation
Validate before calling
if let Some(vendor) = provider_entry.vendor.as_deref() {
assert!(!vendor.is_empty() || provider == "openrouter", "vendor is only valid under providers.openrouter");
} Prevention
- Only write a `vendor` key inside `[providers.openrouter]`.
- When copying provider blocks between entries, strip provider-specific keys like `vendor`.
- Document provider-specific fields in your config templates to avoid copy-over.
When it happens
Trigger: A provider entry in the `providers` config table (not `providers.openrouter`) has a non-empty `vendor` string, and the vendor resolution path (`Config::...vendor` helper at config.rs:5907) processes it.
Common situations: Copying an OpenRouter entry's `vendor` field into another provider block; misunderstanding `vendor` as a generic provider brand field; a migration or merge of provider configs that carried the key over.
Related errors
- Antigravity is a retired, non-runnable legacy provider…
- Antigravity is a retired, non-runnable legacy provider…
- Cannot resume agent on its saved provider
- Choose a model for the destination provider before…
- custom provider ' ' must set [providers. ].kind =…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/3001753ffd43e39a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/config.rs:5907
&providers.modelstudio_coding_plan_anthropic
}
// Handled by the name-keyed early return above (#1519).
ApiProvider::Custom => unreachable!("custom provider resolved by name above"),
})
}
/// Resolve the pin from the selected provider only, before any request.
pub(crate) fn openrouter_vendor(&self) -> Result<Option<String>> {
let provider = self.api_provider();
let Some(vendor) = self
.provider_config_for(provider)
.and_then(|entry| entry.vendor.as_deref())
else {
return Ok(None);
};
let vendor = codewhale_config::validate_openrouter_vendor(vendor)?;
if vendor.is_some() && provider != ApiProvider::Openrouter {
anyhow::bail!("vendor is only supported by providers.openrouter");
}
Ok(vendor.map(str::to_string))
}
pub(crate) fn subagent_provider_config(
&self,
provider: ApiProvider,
) -> Option<&SubagentProviderConfig> {
let providers = self.subagents.as_ref()?.providers.as_ref()?;
providers.iter().find_map(|(key, config)| {
subagent_provider_key_matches(key, provider).then_some(config)
})
}
pub(crate) fn provider_config_for_mut(&mut self, provider: ApiProvider) -> &mut ProviderConfig {
// The custom provider's mutable slot is keyed by the selected
// `provider = "<name>"` value in the flatten map (#1519). Capture the
// name before borrowing `providers` mutably; fall back to a privateView on GitHub (pinned to 73e0f67d83)