Hmbown/CodeWhale · error

MCP exceeded the -page catalog limit

Error message

MCP {} exceeded the {}-page catalog limit

What it means

observe_page enforces a bounded budget on catalog pagination. After recording a page, if the page count exceeds max_pages the operation fails rather than returning a partial catalog. This is a deliberate fail-loud guard against runaway or looping servers.

Solutions

  1. Raise the max_pages catalog budget for this server
  2. Fix/upgrade the MCP server if it paginates abnormally or loops
  3. Filter the catalog server-side to shrink the result set

Example fix

// before
budget: CatalogBudget::new(method, deadline, /*max_pages*/ 10, ...)
// after
budget: CatalogBudget::new(method, deadline, /*max_pages*/ 50, ...)
Defensive patterns

Strategy: try-catch

Validate before calling

// no pre-call check possible; keep budgets above the known catalog page count
assert!(max_pages >= server_page_count_estimate);

Try / catch

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

Prevention

When it happens

Trigger: list_paginated receives a nextCursor for (max_pages+1)-th fetch: pages counter already reached max_pages and the server still advertises more data.

Common situations: Misbehaving MCP server with huge or unbounded resource/prompt/tool lists; cursor loop with fresh cursors; max_pages configured too low for a legitimately large catalog.

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/135ceac8c59517c1. Report an issue: GitHub.

Appendix: source

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

                self.overall_timeout
            );
        }
        Ok(remaining)
    }

    fn observe_page(&mut self, page: &Value, field: &str) -> Result<Option<String>> {
        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
            );

View on GitHub (pinned to 73e0f67d83)