koala73/worldmonitor · error · SafeWebMcpError

Dashboard tab list exceeded the safe output limit.

Error message

Dashboard tab list exceeded the safe output limit.

What it means

The dashboard tab list bounder builds a page of tabs with a nextCursor and validates the serialized page against MAX_OUTPUT_CHARS. If a single page of the tab list still cannot fit within the safe output budget, it throws this SafeWebMcpError instead of returning an oversized result. It guarantees list_dashboard_tabs responses stay within the WebMCP channel limits.

Source

Thrown at src/services/webmcp.ts:1528

  const remaining = tabs.slice(startIndex);
  const page: typeof tabs = [];
  for (let index = 0; index < remaining.length; index += 1) {
    const tab = remaining[index];
    if (!tab) continue;
    const candidate = [...page, tab];
    const following = remaining[index + 1];
    if (JSON.stringify(buildPage(candidate, following?.id)).length > TARGET_OUTPUT_CHARS) {
      break;
    }
    page.push(tab);
  }
  if (page.length === 0 && remaining[0]) page.push(remaining[0]);

  const consumed = startIndex + page.length;
  const nextCursor = consumed < tabs.length ? tabs[consumed]?.id : undefined;
  const result = buildPage(page, nextCursor);
  if (JSON.stringify(result).length > MAX_OUTPUT_CHARS) {
    throw new SafeWebMcpError('Dashboard tab list exceeded the safe output limit.');
  }
  return result;
}

function boundDashboardTabMutation(result: DashboardTabMutationResult): DashboardTabMutationResult {
  const bounded: DashboardTabMutationResult = {
    ok: result.ok === true,
    status: result.status,
    actionType: result.actionType,
    message: boundedText(result.message, 240),
    ...(result.reason ? { reason: boundedText(result.reason, 64) as DashboardTabMutationResult['reason'] } : {}),
    ...(result.tabId ? { tabId: boundedText(result.tabId, 64) } : {}),
    ...(result.name ? { name: boundedText(result.name, DASHBOARD_TAB_NAME_MAX_LENGTH) } : {}),
    ...(result.activeTabId ? { activeTabId: boundedText(result.activeTabId, 64) } : {}),
    ...(result.unchanged === true ? { unchanged: true } : {}),
    ...(result.alreadyExisted === true ? { alreadyExisted: true } : {}),
    ...(typeof result.persisted === 'boolean' ? { persisted: result.persisted } : {}),
    ...(typeof result.tabCount === 'number' ? { tabCount: Math.max(0, Math.floor(result.tabCount)) } : {}),

View on GitHub (pinned to 9361220cc0)

Solutions

  1. Rename or clean up tabs with excessively long names; trim persisted tab state.
  2. Use cursor-based pagination and request the list in multiple calls rather than one large page.
  3. Reset the tab store if it has grown pathologically (export needed tabs, clear, recreate).
  4. If a single tab alone cannot fit the budget, report a bug — the bounder should truncate per-tab fields.

Example fix

// before
const { tabs } = await tools.call('list_dashboard_tabs', { limit: 1000 });
// after
const { tabs } = await tools.call('list_dashboard_tabs', { limit: 20, cursor });
// and keep tab names short when calling create/rename_dashboard_tab
Defensive patterns

Strategy: validation

Validate before calling

function validTabListArgs(args) {
  return (args.limit === undefined || (Number.isInteger(args.limit) && args.limit > 0))
    && (args.cursor === undefined || typeof args.cursor === 'string');
}

Try / catch

try {
  return await tools.call('list_dashboard_tabs', { limit: 20, cursor });
} catch (e) {
  if (e.message.includes('tab list exceeded')) {
    return tools.call('list_dashboard_tabs', { limit: 1, cursor });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling list_dashboard_tabs when even one page of tabs (including the forced first-entry fallback) serializes beyond MAX_OUTPUT_CHARS — e.g. tabs with extremely long names/urls/state blobs.

Common situations: Users with many tabs where each tab object carries verbose metadata; tabs with very long user-chosen names or embedded state; a corrupted/overgrown persisted tab store.

Related errors


AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-09-01). Data as JSON: /api/errors/183777c264db3727. Report an issue: GitHub.