Hmbown/CodeWhale · error
provider catalog scope
Error message
provider catalog scope {key:?} exceeds bounded persistence limits What it means
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.
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
Defensive patterns
Strategy: validation
Validate before calling
let limits = persistence_limits();
let scope_rows = cached_row_count_for(scope_key);
if scope_rows > limits.max_rows {
prune_scope(scope_key, limits.max_rows);
} Try / catch
match bounded_cache_for_persistence(&cache, Some(scope), now, limits) {
Err(e) if e.to_string().contains("exceeds bounded persistence limits") => {
// evict or split the scope, then retry with a smaller cache
}
other => other?,
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.
Related errors
- bounded provider catalog cache exceeds its write limit
- Codewhale terminal receipt contained an invalid count
- Codewhale terminal receipt exceeded its string bound
- Codewhale terminal receipt exceeded its total bound
- Invalid evidence bundle or record limit exceeded.
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/4092201ac66f3525.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/provider_catalog_live.rs:794
mut cache: ProviderCatalogCache,
protected_scope: Option<(&str, &str)>,
now: u64,
limits: CachePersistenceLimits,
) -> Result<ProviderCatalogCache> {
cache
.entries
.retain(|_, entry| !is_account_scoped_scope(&entry.provider, &entry.base_url_fingerprint));
let protected_key = protected_scope
.filter(|(provider, fingerprint)| !is_account_scoped_scope(provider, fingerprint))
.map(|(provider, fingerprint)| ProviderCatalogCache::cache_key(provider, fingerprint));
if let Some(key) = protected_key.as_deref()
&& let Some(entry) = cache.entries.get(key).cloned()
{
let mut protected_only = ProviderCatalogCache::new();
protected_only.entries.insert(key.to_string(), entry);
anyhow::ensure!(
protected_only.entries.len() <= limits.max_scopes.min(MAX_CACHE_SCOPES)
&& cached_row_count(&protected_only) <= limits.max_rows
&& persisted_envelope_len(&protected_only)? <= limits.max_bytes,
"provider catalog scope {key:?} exceeds bounded persistence limits"
);
}
// Rank once while the cache/file locks are held. An older implementation
// reserialized and rescanned the entire envelope for every eviction, which
// made a valid sub-32-MiB file with many tiny scopes quadratic to compact.
let mut eviction_keys = cache
.entries
.iter()
.filter(|(key, _)| protected_key.as_deref() != Some(key.as_str()))
.map(|(key, entry)| {
let health_rank = if matches!(entry.status, CatalogStatus::Failed { .. }) {
0u8
} else if entry.is_stale(now) || matches!(entry.status, CatalogStatus::Stale { .. }) {View on GitHub (pinned to 73e0f67d83)