{"record":{"id":"be3ec1ba3523f81d","repo":"koala73/worldmonitor","slug":"dashboard-tab-result-exceeded-the-safe-output-limi","errorCode":null,"errorMessage":"Dashboard tab result exceeded the safe output limit.","messagePattern":"Dashboard tab result exceeded the safe output limit\\.","errorType":"error_code","errorClass":"SafeWebMcpError","httpStatus":null,"severity":"error","filePath":"src/services/webmcp.ts","lineNumber":1560,"sourceCode":"    ...(typeof result.effectiveCollapsed === 'boolean'\n      ? { effectiveCollapsed: result.effectiveCollapsed }\n      : {}),\n    ...(typeof result.requestedFullscreen === 'boolean'\n      ? { requestedFullscreen: result.requestedFullscreen }\n      : {}),\n    ...(typeof result.effectiveFullscreen === 'boolean'\n      ? { effectiveFullscreen: result.effectiveFullscreen }\n      : {}),\n    ...(ok ? { changed: result.changed === true } : { changed: false }),\n    ...(result.unchanged === true ? { unchanged: true } : {}),\n    ...(typeof result.persisted === 'boolean' ? { persisted: result.persisted } : {}),\n    ...(!ok && reason ? { reason } : {}),\n    message: boundedText(result.message, 160) || (ok ? 'Panel layout updated.' : 'Panel layout change denied.'),\n  };\n}\n\nfunction boundDashboardTabList(\n  snapshot: DashboardTabListSnapshot,\n  cursor?: string,\n): DashboardTabActionResult {\n  const sourceTabs = Array.isArray(snapshot.tabs) ? snapshot.tabs : [];\n  const tabs = sourceTabs.map((tab) => ({\n    id: boundedText(tab?.id, 64),\n    name: boundedText(tab?.name, DASHBOARD_TAB_NAME_MAX_LENGTH),\n    active: tab?.active === true,\n    canDelete: tab?.canDelete === true,\n  })).filter((tab) => tab.id);\n  const tabCount = Math.max(\n    Math.max(0, Math.floor(boundedNumber(snapshot.tabCount)) || tabs.length),\n    tabs.length,\n  );\n  const activeTabId = boundedText(snapshot.activeTabId, 64);\n  const canCreate = snapshot.canCreate === true;\n  const cap = snapshot.cap === null || typeof snapshot.cap === 'number' ? snapshot.cap : null;\n  const createBlockReason = snapshot.createBlockReason\n    ? boundedText(snapshot.createBlockReason, 32) as DashboardTabListSnapshot['createBlockReason']","sourceCodeStart":1542,"sourceCodeEnd":1578,"githubUrl":"https://github.com/koala73/worldmonitor/blob/e586b8b4b80f595aa7ece295eec10d76f2921240/src/services/webmcp.ts#L1542-L1578","documentation":"boundDashboardTabMutation sanitizes a tab mutation result (create/rename/delete/select), coercing counts, capping lockReason to 32 chars, and then asserts the serialized result fits MAX_OUTPUT_CHARS. If it still exceeds the budget it throws this SafeWebMcpError. Mutation results are tiny by design, so hitting this indicates the result structurally ballooned beyond what the bounder can trim.","triggerScenarios":"A create_dashboard_tab / rename_dashboard_tab / delete_dashboard_tab / select_dashboard_tab call whose bounded result object still serializes above MAX_OUTPUT_CHARS — practically only when the result carries oversized fields the bounder does not truncate.","commonSituations":"A dashboard version returning extra unbounded fields in the mutation result; extremely long tab ids or lockReason variants; a regression where the bounder's field whitelist stopped covering a new large field.","solutions":["Retry the mutation once; this is not expected in normal operation and may be transient state.","Check whether you are on a dashboard version that added fields to DashboardTabMutationResult; upgrade or downgrade to a matched pair of tool/app versions.","Shorten the tab name/id you are mutating to rule out oversize user input.","Report a bug with the tool name and args — the bounder should always produce a sub-budget mutation result."],"exampleFix":"// before\nawait tools.call('rename_dashboard_tab', { id, name: 'x'.repeat(5000) });\n// after\nawait tools.call('rename_dashboard_tab', { id, name: name.slice(0, 64) });","handlingStrategy":"try-catch","validationCode":"function validTabMutationArgs(args) {\n  return typeof args.id === 'string' && args.id.length <= 128\n    && (args.name === undefined || (typeof args.name === 'string' && args.name.length <= 64));\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await tools.call('rename_dashboard_tab', { id, name });\n} catch (e) {\n  if (e.message.includes('tab result exceeded')) {\n    // unexpected: mutation results are tiny; log and retry once, then report\n    console.error('oversized tab mutation result', { id, name: name.length });\n    return tools.call('rename_dashboard_tab', { id, name: name.slice(0, 32) });\n  }\n  throw e;\n}","preventionTips":["Bound user-supplied tab names to a sane length (<= 64 chars) before calling.","Keep tab ids short and generated, not free-form user text.","Keep tool and dashboard versions matched.","Treat occurrences as a bug-report condition with args captured."],"tags":["webmcp","output-budget","tabs","mutation"],"backgroundTag":"response-size-limit-exceeded","analyzedSha":"e586b8b4b80f595aa7ece295eec10d76f2921240","analyzedAt":"2026-09-01T10:32:37.851Z","contentChangedAt":"2026-09-01T10:32:37.851Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}