{"record":{"id":"bbb0f6ebed3a502f","repo":"Hmbown/CodeWhale","slug":"providers-openrouter-vendor-must-be-an-openrouter-slug","errorCode":null,"errorMessage":"providers.openrouter.vendor must be an OpenRouter slug without whitespace or control characters","messagePattern":"providers\\.openrouter\\.vendor must be an OpenRouter slug without whitespace or control characters","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/config/src/lib.rs","lineNumber":147,"sourceCode":"    // Configured gateways use more credential dialects than the three headers\n    // generated by Codewhale itself. `auth_mode = \"none\"` is an endpoint\n    // contract, so suppress every credential-shaped request header instead of\n    // allowing the same secret through Proxy-Authorization, X-Auth-Token,\n    // X-Access-Token, X-Goog-Api-Key, or another *-token/*-api-key spelling.\n    is_sensitive_config_key(name) || name.eq_ignore_ascii_case(\"cookie\")\n}\n\n/// Preserve OpenRouter endpoint slugs verbatim; an empty value clears a pin.\n/// The service owns the vendor catalog, so validation must not freeze one here.\npub fn validate_openrouter_vendor(value: &str) -> Result<Option<&str>> {\n    if value.trim().is_empty() {\n        return Ok(None);\n    }\n    if value\n        .chars()\n        .any(|ch| ch.is_whitespace() || ch.is_control())\n    {\n        bail!(\n            \"providers.openrouter.vendor must be an OpenRouter slug without whitespace or control characters\"\n        );\n    }\n    Ok(Some(value))\n}\n\n/// Apply a validated pin to an OpenRouter request without dropping unrelated\n/// caller policies such as data collection or zero-data-retention constraints.\npub fn apply_openrouter_vendor(body: &mut serde_json::Value, vendor: Option<&str>) {\n    if let Some(vendor) = vendor {\n        if !body[\"provider\"].is_object() {\n            body[\"provider\"] = serde_json::json!({});\n        }\n        body[\"provider\"][\"order\"] = serde_json::json!([vendor]);\n        body[\"provider\"][\"allow_fallbacks\"] = serde_json::json!(false);\n    }\n}\n","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/config/src/lib.rs#L129-L165","documentation":"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.","triggerScenarios":"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\"`.","commonSituations":"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.","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."],"exampleFix":"// before\n[providers.openrouter]\nvendor = \"Open AI\"\n// after\n[providers.openrouter]\nvendor = \"openai\"","handlingStrategy":"validation","validationCode":"fn valid_openrouter_vendor(v: &str) -> bool {\n    !v.is_empty() && !v.chars().any(|c| c.is_whitespace() || c.is_control())\n}","typeGuard":null,"tryCatchPattern":"match set_provider_config_value(config, ProviderKind::Openrouter, ProviderConfigField::Vendor, value) {\n    Err(e) if e.to_string().contains(\"without whitespace\") => {\n        let cleaned = value.trim();\n        if valid_openrouter_vendor(cleaned) { retry_with(cleaned)? } else { return Err(e) }\n    }\n    other => other,\n}","preventionTips":["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."],"tags":["config","validation","openrouter"],"backgroundTag":"invalid-config-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}