Hmbown/CodeWhale · error
providers.openrouter.vendor must be an OpenRouter slug…
Error message
providers.openrouter.vendor must be an OpenRouter slug without whitespace or control characters
What it means
Thrown by `validate_openrouter_vendor` when the `providers.openrouter.vendor` config value contains whitespace or control characters. OpenRouter vendor values are slugs (e.g. "openai", "meta-llama") and must be clean identifier strings; this check runs after the empty/None cases.
Solutions
- Use the exact OpenRouter slug (lowercase, hyphen-separated, no spaces) e.g. "meta-llama".
- Trim the value and remove any embedded whitespace or control characters before setting it.
- Verify the vendor slug against OpenRouter's model listing before writing it to config.
Example fix
// before [providers.openrouter] vendor = "Open AI" // after [providers.openrouter] vendor = "openai"
Defensive patterns
Strategy: validation
Validate before calling
fn valid_openrouter_vendor(v: &str) -> bool {
!v.is_empty() && !v.chars().any(|c| c.is_whitespace() || c.is_control())
} Try / catch
match set_provider_config_value(config, ProviderKind::Openrouter, ProviderConfigField::Vendor, value) {
Err(e) if e.to_string().contains("without whitespace") => {
let cleaned = value.trim();
if valid_openrouter_vendor(cleaned) { retry_with(cleaned)? } else { return Err(e) }
}
other => other,
} Prevention
- Use lowercase slugs from OpenRouter's model listing, never display names.
- Trim user input before writing vendor values to config.
- Reject vendor strings containing spaces at input time in any UI/script.
When it happens
Trigger: Calling `set_provider_config_value` with `ProviderConfigField::Vendor` and a value containing spaces, tabs, newlines, quotes with surrounding whitespace, or control characters — e.g. `"open ai"`, `"openai\n"`.
Common situations: Pasting a vendor display name ("Open AI") instead of the slug ("openai") into config; a TOML value accidentally including a trailing newline or invisible control character from copy-paste.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- agent profile provider cannot be empty
- agent profile provider must be a simple provider id
- api_key cannot be empty string
- approval_policy ' ' is not allowed by requirements ( )
- budget document_kind must be
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/bbb0f6ebed3a502f.
Report an issue: GitHub.
Appendix: source
Thrown at crates/config/src/lib.rs:147
// Configured gateways use more credential dialects than the three headers
// generated by Codewhale itself. `auth_mode = "none"` is an endpoint
// contract, so suppress every credential-shaped request header instead of
// allowing the same secret through Proxy-Authorization, X-Auth-Token,
// X-Access-Token, X-Goog-Api-Key, or another *-token/*-api-key spelling.
is_sensitive_config_key(name) || name.eq_ignore_ascii_case("cookie")
}
/// Preserve OpenRouter endpoint slugs verbatim; an empty value clears a pin.
/// The service owns the vendor catalog, so validation must not freeze one here.
pub fn validate_openrouter_vendor(value: &str) -> Result<Option<&str>> {
if value.trim().is_empty() {
return Ok(None);
}
if value
.chars()
.any(|ch| ch.is_whitespace() || ch.is_control())
{
bail!(
"providers.openrouter.vendor must be an OpenRouter slug without whitespace or control characters"
);
}
Ok(Some(value))
}
/// Apply a validated pin to an OpenRouter request without dropping unrelated
/// caller policies such as data collection or zero-data-retention constraints.
pub fn apply_openrouter_vendor(body: &mut serde_json::Value, vendor: Option<&str>) {
if let Some(vendor) = vendor {
if !body["provider"].is_object() {
body["provider"] = serde_json::json!({});
}
body["provider"]["order"] = serde_json::json!([vendor]);
body["provider"]["allow_fallbacks"] = serde_json::json!(false);
}
}
View on GitHub (pinned to 73e0f67d83)