{"record":{"id":"4092201ac66f3525","repo":"Hmbown/CodeWhale","slug":"provider-catalog-scope-key-exceeds-bounded-persistence","errorCode":null,"errorMessage":"provider catalog scope {key:?} exceeds bounded persistence limits","messagePattern":"provider catalog scope (.+?) exceeds bounded persistence limits","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/provider_catalog_live.rs","lineNumber":794,"sourceCode":"    mut cache: ProviderCatalogCache,\n    protected_scope: Option<(&str, &str)>,\n    now: u64,\n    limits: CachePersistenceLimits,\n) -> Result<ProviderCatalogCache> {\n    cache\n        .entries\n        .retain(|_, entry| !is_account_scoped_scope(&entry.provider, &entry.base_url_fingerprint));\n\n    let protected_key = protected_scope\n        .filter(|(provider, fingerprint)| !is_account_scoped_scope(provider, fingerprint))\n        .map(|(provider, fingerprint)| ProviderCatalogCache::cache_key(provider, fingerprint));\n\n    if let Some(key) = protected_key.as_deref()\n        && let Some(entry) = cache.entries.get(key).cloned()\n    {\n        let mut protected_only = ProviderCatalogCache::new();\n        protected_only.entries.insert(key.to_string(), entry);\n        anyhow::ensure!(\n            protected_only.entries.len() <= limits.max_scopes.min(MAX_CACHE_SCOPES)\n                && cached_row_count(&protected_only) <= limits.max_rows\n                && persisted_envelope_len(&protected_only)? <= limits.max_bytes,\n            \"provider catalog scope {key:?} exceeds bounded persistence limits\"\n        );\n    }\n\n    // Rank once while the cache/file locks are held. An older implementation\n    // reserialized and rescanned the entire envelope for every eviction, which\n    // made a valid sub-32-MiB file with many tiny scopes quadratic to compact.\n    let mut eviction_keys = cache\n        .entries\n        .iter()\n        .filter(|(key, _)| protected_key.as_deref() != Some(key.as_str()))\n        .map(|(key, entry)| {\n            let health_rank = if matches!(entry.status, CatalogStatus::Failed { .. }) {\n                0u8\n            } else if entry.is_stale(now) || matches!(entry.status, CatalogStatus::Stale { .. }) {","sourceCodeStart":776,"sourceCodeEnd":812,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/provider_catalog_live.rs#L776-L812","documentation":"bounded_cache_for_persistence enforces per-scope persistence limits (max scopes, max rows, max bytes). When a single protected scope alone — serialized as its own cache — exceeds any of these limits, it cannot be persisted within bounds and this ensure! fails.","triggerScenarios":"Persisting or compacting the catalog cache when the protected scope contains more providers/rows than limits.max_rows, or its JSON envelope exceeds limits.max_bytes, or entries count exceeds min(max_scopes, MAX_CACHE_SCOPES).","commonSituations":"A user or a test registers an enormous number of custom catalog providers in one scope; limits were tightened by config while an old large scope remains on disk.","solutions":["Reduce the number of providers/rows in the offending scope (prune stale or duplicate entries)","Split the scope's contents across multiple scopes so no single scope exceeds limits","Raise the persistence limits if the data is legitimately required","Delete the oversized scope from the on-disk cache and let it be rebuilt incrementally"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"let limits = persistence_limits();\nlet scope_rows = cached_row_count_for(scope_key);\nif scope_rows > limits.max_rows {\n    prune_scope(scope_key, limits.max_rows);\n}","typeGuard":null,"tryCatchPattern":"match bounded_cache_for_persistence(&cache, Some(scope), now, limits) {\n    Err(e) if e.to_string().contains(\"exceeds bounded persistence limits\") => {\n        // evict or split the scope, then retry with a smaller cache\n    }\n    other => other?,\n}","preventionTips":["Keep custom provider scopes small; prune stale entries regularly","Split large catalogs across multiple scopes","When lowering limits in config, also clear or compact the existing on-disk cache","Monitor scope size before persisting"],"tags":["cache","limits","persistence","validation"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T16:17:23.217Z"}