Hmbown/CodeWhale · critical
bundled model catalog must parse
Error message
bundled model catalog must parse
What it means
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.
Source
Thrown at crates/tui/src/model_catalog.rs:166
#[must_use]
pub fn resolved_max_output(model: &str) -> Option<u32> {
resolved_entry(model).and_then(|entry| entry.max_output)
}
#[must_use]
pub fn resolved_supports_reasoning(model: &str) -> Option<bool> {
resolved_entry(model).and_then(|entry| entry.supports_reasoning)
}
#[must_use]
#[cfg_attr(test, allow(dead_code))]
pub fn resolved_usd_pricing(model: &str) -> Option<(f64, f64)> {
let entry = resolved_entry(model)?;
Some((entry.input_usd_per_million?, entry.output_usd_per_million?))
}
pub fn bundled_catalog() -> CatalogCache {
serde_json::from_str(BUNDLED_CATALOG_JSON).expect("bundled model catalog must parse")
}
fn catalog_cache_read_path() -> Result<PathBuf> {
Ok(codewhale_config::resolve_state_dir("catalog")?.join(OPENROUTER_CACHE_FILE))
}
pub fn load_cached() -> Option<CatalogCache> {
let path = catalog_cache_read_path().ok()?;
let raw = std::fs::read_to_string(path).ok()?;
serde_json::from_str(&raw).ok()
}
#[cfg(test)]
static TEST_CATALOG_LOCK: std::sync::LazyLock<std::sync::Mutex<()>> =
std::sync::LazyLock::new(|| std::sync::Mutex::new(()));
#[cfg(test)]
pub(crate) fn test_catalog_lock() -> std::sync::MutexGuard<'static, ()> {View on GitHub (pinned to 0c42157ee5)
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.
Example fix
// before
serde_json::from_str(BUNDLED_CATALOG_JSON).expect("bundled model catalog must parse")
// after: keep the panic but pin the invariant with a CI test so drift is caught pre-release
#[test]
fn bundled_catalog_parses() {
let catalog = bundled_catalog();
assert!(!catalog.entries().is_empty());
} Defensive patterns
Strategy: fallback
Validate before calling
// Prefer the on-disk cache when present; it survives schema drift in the binary
if let Some(cached) = model_catalog::load_cached() {
// use cached entries instead of relying on the bundled asset
} Try / catch
let catalog = std::panic::catch_unwind(model_catalog::bundled_catalog)
.ok()
.or_else(model_catalog::load_cached);
let catalog = catalog.expect("neither bundled nor cached model catalog is usable"); Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- runtime event JSON is serializable
- validated Fleet tool authority envelope must serialize
- ApplyPatchPreflight should serialize
- validated sandbox permission
- sandbox escalation was validated while planning
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/caa4aa38d179fa5e.
Report an issue: GitHub.