{"record":{"id":"caa4aa38d179fa5e","repo":"Hmbown/CodeWhale","slug":"bundled-model-catalog-must-parse","errorCode":null,"errorMessage":"bundled model catalog must parse","messagePattern":"bundled model catalog must parse","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/tui/src/model_catalog.rs","lineNumber":166,"sourceCode":"#[must_use]\npub fn resolved_max_output(model: &str) -> Option<u32> {\n    resolved_entry(model).and_then(|entry| entry.max_output)\n}\n\n#[must_use]\npub fn resolved_supports_reasoning(model: &str) -> Option<bool> {\n    resolved_entry(model).and_then(|entry| entry.supports_reasoning)\n}\n\n#[must_use]\n#[cfg_attr(test, allow(dead_code))]\npub fn resolved_usd_pricing(model: &str) -> Option<(f64, f64)> {\n    let entry = resolved_entry(model)?;\n    Some((entry.input_usd_per_million?, entry.output_usd_per_million?))\n}\n\npub fn bundled_catalog() -> CatalogCache {\n    serde_json::from_str(BUNDLED_CATALOG_JSON).expect(\"bundled model catalog must parse\")\n}\n\nfn catalog_cache_read_path() -> Result<PathBuf> {\n    Ok(codewhale_config::resolve_state_dir(\"catalog\")?.join(OPENROUTER_CACHE_FILE))\n}\n\npub fn load_cached() -> Option<CatalogCache> {\n    let path = catalog_cache_read_path().ok()?;\n    let raw = std::fs::read_to_string(path).ok()?;\n    serde_json::from_str(&raw).ok()\n}\n\n#[cfg(test)]\nstatic TEST_CATALOG_LOCK: std::sync::LazyLock<std::sync::Mutex<()>> =\n    std::sync::LazyLock::new(|| std::sync::Mutex::new(()));\n\n#[cfg(test)]\npub(crate) fn test_catalog_lock() -> std::sync::MutexGuard<'static, ()> {","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/model_catalog.rs#L148-L184","documentation":"Panic loading the model catalog compiled into the binary: `BUNDLED_CATALOG_JSON` is `include_str!(\"../assets/model_catalog.bundled.json\")` (model_catalog.rs:16) and `bundled_catalog()` parses it into `CatalogCache`. Because the asset is checked in at build time, failure means the JSON file and the `CatalogCache` deserialization type are out of sync — a renamed/retyped field, truncated file, or schema-version mismatch — not a runtime condition on the user's machine.","triggerScenarios":"Editing `crates/tui/assets/model_catalog.bundled.json` or the `CatalogCache`/entry structs without keeping both in sync; a partial merge of the asset; release automation regenerating the asset with a different schema. The first `resolved_*` call after such a build panics at model_catalog.rs:166.","commonSituations":"Branches that changed pricing/capability fields; a stale or corrupted checkout mixing an old asset with new code; CI builds that never execute the catalog parse path before shipping.","solutions":["Fix the asset or the struct so they agree, then rebuild — verify with a direct parse of the asset in a scratch test.","Add/keep a smoke unit test calling `bundled_catalog()` so schema drift fails `cargo test -p codewhale-tui` instead of the first user keystroke.","If the binary came from elsewhere, reinstall/rebuild from a clean checkout.","Cross-check the catalog `schema_version` constant between the asset and code."],"exampleFix":"// before\nserde_json::from_str(BUNDLED_CATALOG_JSON).expect(\"bundled model catalog must parse\")\n\n// after: keep the panic but pin the invariant with a CI test so drift is caught pre-release\n#[test]\nfn bundled_catalog_parses() {\n    let catalog = bundled_catalog();\n    assert!(!catalog.entries().is_empty());\n}","handlingStrategy":"fallback","validationCode":"// Prefer the on-disk cache when present; it survives schema drift in the binary\nif let Some(cached) = model_catalog::load_cached() {\n    // use cached entries instead of relying on the bundled asset\n}","typeGuard":null,"tryCatchPattern":"let catalog = std::panic::catch_unwind(model_catalog::bundled_catalog)\n    .ok()\n    .or_else(model_catalog::load_cached);\nlet catalog = catalog.expect(\"neither bundled nor cached model catalog is usable\");","preventionTips":["Run `cargo test -p codewhale-tui` on any change to `assets/model_catalog.bundled.json` or `CatalogCache`.","Rebuild/reinstall from a clean checkout after catalog schema changes; never mix an old binary with new assets."],"tags":["rust","serde-json","model-catalog","build-asset","panic","expect"],"backgroundTag":"json-parse-error","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}