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

  1. Remove the `vendor` key from the non-OpenRouter provider entry in your config.
  2. If you meant to use a vendor-qualified OpenRouter route, move the `vendor` setting under `providers.openrouter`.
  3. 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

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


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 private

View on GitHub (pinned to 73e0f67d83)