Hmbown/CodeWhale · error

MCP exceeded the -item catalog limit

Error message

MCP {} exceeded the {}-item catalog limit

What it means

observe_page tracks the cumulative number of catalog items seen across pages. When the total exceeds max_items, the whole listing fails instead of silently returning a truncated catalog, honoring the fail-loud budget contract.

Solutions

  1. Increase max_items in the catalog budget
  2. Reduce the server's exposed catalog size (namespacing/filtering tools)
  3. Check for a server bug that re-lists the same items on every page

Example fix

// before
max_items: 100
// after
max_items: 1000
Defensive patterns

Strategy: try-catch

Validate before calling

// estimate expected item volume before listing
let expected_items = known_tool_count + known_resource_count;
assert!(max_items >= expected_items, "max_items below expected catalog size");

Try / catch

match client.list_resources_with_metadata().await {
    Ok(entries) => use(entries),
    Err(e) if e.to_string().contains("-item catalog limit") => {
        eprintln!("catalog exceeds item budget: {}", e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: list_paginated accumulates items across successive pages and the running total (self.items) surpasses max_items after a page is observed.

Common situations: Very large MCP server catalogs (thousands of tools/resources); max_items tuned for a smaller deployment; a server bug duplicating entries across pages.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/b847168dc32fd7f8. Report an issue: GitHub.

Appendix: source

Thrown at crates/mcp/src/stdio_client.rs:376

        let values = page.get(field).and_then(Value::as_array).with_context(|| {
            format!(
                "MCP {} response did not contain a '{field}' array",
                self.method
            )
        })?;

        self.pages = self.pages.saturating_add(1);
        self.items = self.items.saturating_add(values.len());
        self.bytes = self.bytes.saturating_add(serde_json::to_vec(page)?.len());
        if self.pages > self.max_pages {
            bail!(
                "MCP {} exceeded the {}-page catalog limit",
                self.method,
                self.max_pages
            );
        }
        if self.items > self.max_items {
            bail!(
                "MCP {} exceeded the {}-item catalog limit",
                self.method,
                self.max_items
            );
        }
        if self.bytes > self.max_bytes {
            bail!(
                "MCP {} exceeded the {}-byte aggregate catalog limit",
                self.method,
                self.max_bytes
            );
        }

        let next_cursor = match page.get("nextCursor") {
            None => None,
            Some(Value::String(cursor)) => Some(cursor.clone()),
            Some(_) => bail!("MCP {} returned a non-string nextCursor", self.method),
        };

View on GitHub (pinned to 73e0f67d83)