tinyhumansai/openhuman · warning
MCP official deep-page walk refused: page={target_page} > MA
Error message
MCP official deep-page walk refused: page={target_page} > MAX_CURSOR_WALK_PAGES={MAX_CURSOR_WALK_PAGES} What it means
The registry's cursor walk (fetching page after page to reach a deep `target_page` for offset-style pagination emulation) refuses targets beyond `MAX_CURSOR_WALK_PAGES` (50). To show page N of cursor-paginated results, the client must walk cursors 2..N sequentially; beyond 50 that costs 50+ network fetches for one view, so it bails with this guard (a `[mcp-official] walk refused` warn is logged).
Source
Thrown at src/openhuman/mcp/registry/registries/mcp_official.rs:302
/// `None` if the cursor chain ran out before reaching `target_page`.
///
/// Bails after [`MAX_CURSOR_WALK_PAGES`] iterations to keep a single user
/// request from fanning into hundreds of upstream calls.
async fn walk_cursor_for_page(
config: &Config,
q: &str,
limit: u32,
target_page: u32,
) -> Result<Option<String>> {
if target_page <= 1 {
return Ok(None);
}
if target_page > MAX_CURSOR_WALK_PAGES {
tracing::warn!(
"[mcp-official] walk refused has_query={} target_page={target_page} max={MAX_CURSOR_WALK_PAGES}",
!q.is_empty()
);
anyhow::bail!(
"MCP official deep-page walk refused: page={target_page} > MAX_CURSOR_WALK_PAGES={MAX_CURSOR_WALK_PAGES}"
);
}
tracing::debug!(
"[mcp-official] walk start has_query={} q_len={} target_page={target_page} limit={limit}",
!q.is_empty(),
q.len()
);
let mut cursor: Option<String> = None;
let mut net_fetches = 0u32;
let mut cache_fetches = 0u32;
// We need the cursor that produces `target_page`, which is the cursor
// returned by the response for `target_page - 1`.
for page in 1..target_page {
let cache_key = format!("mcp_official:search:{q}:{page}:{limit}");
View on GitHub (pinned to 7491200858)
Solutions
- Cap user-facing page navigation at 50, or narrow the search query so results fit in fewer pages.
- Replace jump-to-page with cursor-based next/prev navigation (reuse the returned cursor instead of computing page numbers).
- If you truly need the whole catalog, walk cursors forward yourself at a sane rate rather than jumping to a deep page.
- Persist the current cursor, not the page number, so restoring state never requests a deep page.
Example fix
// before let page = user_requested_page; // can be 500 let page = page.clamp(1, 50); // runtime still refuses 500 // after — clamp at the UI boundary AND drive by cursor const MAX_PAGES = 50; const page = Math.min(Math.max(1, user_requested_page), MAX_PAGES); // or: navigate with nextCursor returned by the previous response
Defensive patterns
Strategy: validation
Validate before calling
const MAX_CURSOR_WALK_PAGES: u32 = 50; let target = requested_page.min(MAX_CURSOR_WALK_PAGES).max(1); // refuse earlier with a clear message instead of letting the walk bail deep in the client
Prevention
- Bound page inputs in the UI at 50 and steer users to refine the query instead.
- Persist cursors, not page numbers, so restored views never request deep pages.
- For full-catalog needs, iterate cursors forward incrementally rather than jumping.
When it happens
Trigger: A user or API consumer requesting `page > 50` of official-registry search results; UIs that compute page numbers from a total-count/limit estimate and land beyond the cap; saved deep-link pagination state.
Common situations: Long result sets with a jump-to-page control; UIs exposing numeric page input without a bound; scripts paginating the whole catalog by incrementing page numbers.
Related errors
- MCP official registry returned HTTP {status}: {}
- [mcp-registry] http_remote server_id={} has empty deployment
- MCP official registry GET {qualified_name} returned HTTP {st
- Smithery returned HTTP {status}: {}
- Smithery GET {qualified_name} returned HTTP {status}: {}
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/0286137736b86f45.
Report an issue: GitHub.