{"record":{"id":"edf409657c3ed027","repo":"zeroclaw-labs/zeroclaw","slug":"openrouter-catalog-has-no-entries-under-vendor-pre","errorCode":null,"errorMessage":"OpenRouter catalog has no entries under vendor prefix {vendor_prefix:?}","messagePattern":"OpenRouter catalog has no entries under vendor prefix (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/openrouter_catalog.rs","lineNumber":94,"sourceCode":"        .into_iter()\n        .map(|m| ModelEntryWithPricing {\n            id: m.id,\n            pricing: m.pricing,\n        })\n        .collect())\n}\n\n/// Filter a parsed catalog by vendor prefix, returning the slug portion of\n/// each match. Sorted and deduped. Errors if nothing matches. Pure —\n/// separated from the live fetch so it can be unit-tested.\npub(crate) fn filter_by_vendor(catalog: &[String], vendor_prefix: &str) -> Result<Vec<String>> {\n    let needle = format!(\"{vendor_prefix}/\");\n    let mut slugs: Vec<String> = catalog\n        .iter()\n        .filter_map(|id| id.strip_prefix(&needle).map(ToString::to_string))\n        .collect();\n    if slugs.is_empty() {\n        anyhow::bail!(\"OpenRouter catalog has no entries under vendor prefix {vendor_prefix:?}\");\n    }\n    slugs.sort();\n    slugs.dedup();\n    Ok(slugs)\n}\n\n/// Filter an enriched catalog by vendor prefix, returning model entries with\n/// pricing. Sorted and deduped by id.\nfn filter_by_vendor_with_pricing(\n    catalog: &[ModelEntryWithPricing],\n    vendor_prefix: &str,\n) -> Result<Vec<zeroclaw_api::model_provider::ModelInfo>> {\n    use zeroclaw_api::model_provider::ModelInfo;\n    let needle = format!(\"{vendor_prefix}/\");\n    let mut models: Vec<ModelInfo> = catalog\n        .iter()\n        .filter_map(|e| {\n            e.id.strip_prefix(&needle).map(|slug| ModelInfo {","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/openrouter_catalog.rs#L76-L112","documentation":"list_models_for_vendor fetched OpenRouter's public /api/v1/models catalog successfully, then filter_by_vendor found zero model ids starting with \"{vendor_prefix}/\". The vendor prefix is the segment before the first slash in an OpenRouter id (e.g. anthropic, openai, x-ai); the call errors rather than returning an empty list so callers never mistake 'no such vendor' for 'vendor has no models'.","triggerScenarios":"Calling list_models_for_vendor with a trailing slash (\"anthropic/\" makes the needle \"anthropic//\" and matches nothing); a misspelled vendor slug (\"google-deepmind\" vs \"google\"); passing a full model id (\"anthropic/claude-3.5-sonnet\") as the vendor argument.","commonSituations":"Hardcoding vendor names guessed from marketing names instead of reading actual catalog ids; OpenRouter renaming or delisting a vendor; code written against an old catalog snapshot.","solutions":["Pass only the segment before the slash: \"anthropic\", not \"anthropic/\" and not the full model id.","List the full catalog (list_models) and read the real prefixes before filtering.","If the prefix still fails, confirm the vendor exists at openrouter.ai/models — it may have been renamed or delisted."],"exampleFix":"// before — trailing slash and full-id forms match nothing\nlist_models_for_vendor(\"anthropic/\").await?;\n\n// after — bare vendor segment\nlist_models_for_vendor(\"anthropic\").await?;","handlingStrategy":"validation","validationCode":"// Verify the prefix exists before filtering\nlet catalog = list_models().await?;\nlet needle = format!(\"{vendor}/\");\nanyhow::ensure!(\n    catalog.iter().any(|id| id.starts_with(&needle)),\n    \"unknown vendor {vendor}; call list_models() to see real prefixes\"\n);","typeGuard":"fn vendor_exists(catalog: &[String], vendor: &str) -> bool {\n    catalog.iter().any(|id| id.starts_with(&format!(\"{vendor}/\")))\n}","tryCatchPattern":"Catch the empty-filter error and fall back to listing the full catalog so the user can pick a real vendor prefix; do not retry — the fetched catalog is cached (OnceCell) and will not change within the process.","preventionTips":["Derive vendor dropdowns from the live catalog, not hardcoded lists","Pass the bare segment before '/' — never a trailing slash or a full model id","Re-check prefixes after OpenRouter catalog updates"],"tags":["openrouter","model-catalog","validation","vendor-prefix"],"backgroundTag":"unknown-model-vendor","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}