{"record":{"id":"f555ab5144cc1cc9","repo":"ruvnet/ruflo","slug":"peer-peer-nodeid-response-exceeds-size-cap","errorCode":null,"errorMessage":"peer ${peer.nodeId} response exceeds size cap","messagePattern":"peer (.+?) response exceeds size cap","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/mcp-tools/agentbbs-federation.ts","lineNumber":394,"sourceCode":"/** Pull one room from one peer and merge what verifies. */\nexport async function syncRoomFromPeer(\n  basePath: string,\n  peer: FederationPeer,\n  roomId: string,\n  fetchImpl: typeof fetch = fetch,\n): Promise<MergeResult & { peerNodeId: string; roomId: string }> {\n  validateRoomId(roomId);\n  const since = peer.lastSeq?.[roomId] ?? 0;\n  const url = `${peer.url}/agentbbs/v1/rooms/${encodeURIComponent(roomId)}/envelopes?since=${since}`;\n\n  const controller = new AbortController();\n  const timer = setTimeout(() => controller.abort(), SYNC_TIMEOUT_MS);\n  let body: any;\n  try {\n    const res = await fetchImpl(url, { signal: controller.signal, headers: { accept: 'application/json' } });\n    if (!res.ok) throw new Error(`peer ${peer.nodeId} returned ${res.status}`);\n    const text = await res.text();\n    if (text.length > MAX_SYNC_RESPONSE_BYTES) throw new Error(`peer ${peer.nodeId} response exceeds size cap`);\n    body = JSON.parse(text);\n  } finally {\n    clearTimeout(timer);\n  }\n\n  const envelopes: SignedEnvelope[] = Array.isArray(body?.envelopes) ? body.envelopes : [];\n  const merged = await mergeEnvelopes(basePath, roomId, envelopes, peer.publicKey);\n\n  const peers = readPeers(basePath);\n  const rec = peers.find(p => p.nodeId === peer.nodeId);\n  if (rec) {\n    rec.lastSyncedAt = new Date().toISOString();\n    rec.lastSeq = rec.lastSeq ?? {};\n    const maxSeq = envelopes.reduce((m, e) => Math.max(m, Number(e.seq) || 0), since);\n    rec.lastSeq[roomId] = maxSeq;\n    writePeers(basePath, peers);\n  }\n  return { ...merged, peerNodeId: peer.nodeId, roomId };","sourceCodeStart":376,"sourceCodeEnd":412,"githubUrl":"https://github.com/ruvnet/ruflo/blob/2602b642d92234c710ffbe96bfb33007d481ceab/v3/@claude-flow/cli/src/mcp-tools/agentbbs-federation.ts#L376-L412","documentation":"syncRoomFromPeer enforces MAX_SYNC_RESPONSE_BYTES on the peer's response body before parsing. The error means the peer returned a response larger than the configured cap, so the client refuses to read/parse it to bound memory usage from malicious or misbehaving peers.","triggerScenarios":"Syncing a room whose peer has accumulated an envelope backlog exceeding MAX_SYNC_RESPONSE_BYTES, or a malicious/misconfigured peer returning an oversized (or unbounded) payload for the sync URL.","commonSituations":"Long-lived room with months of unmerged envelopes; peer ignoring since/limit parameters and returning everything; a compromised or buggy peer streaming an arbitrary-size response.","solutions":["Sync more frequently so the incremental delta per sync stays under the size cap.","If the peer supports query parameters, narrow the sync window (since/limit) to reduce response size.","If the backlog is legitimately large, prune/compact envelopes on the peer or raise MAX_SYNC_RESPONSE_BYTES deliberately for that deployment (trade-off: more memory per sync).","Investigate the peer if the size is implausible — an oversized response may indicate a misbehaving or hostile node."],"exampleFix":"// before\nawait syncRoomFromPeer(peer, roomId); // huge backlog -> size cap error\n// after\nfor (const window of [3600, 86400, 604800]) { // grow until under cap\n  try { await syncRoomFromPeer(peer, roomId, { sinceSeconds: window }); break; }\n  catch (e) { if (!/size cap/.test(e.message)) throw e; }\n}","handlingStrategy":"fallback","validationCode":"// preflight: request a small window first\nconst probe = await fetch(syncUrl + '?since=3600');\nconst len = Number(probe.headers.get('content-length') ?? 0);\nif (len > MAX_SYNC_RESPONSE_BYTES) console.warn('response would exceed size cap');","typeGuard":"function isWithinCap(text: string, cap: number): boolean { return text.length <= cap; }","tryCatchPattern":"try {\n  await syncRoomFromPeer(peer, roomId);\n} catch (e) {\n  if (/response exceeds size cap/.test(e.message)) {\n    await syncRoomFromPeer(peer, roomId, { sinceSeconds: 3600 }); // smaller delta\n    return;\n  }\n  throw e;\n}","preventionTips":["Sync rooms frequently to keep deltas small","Use since/limit query parameters to bound responses","Flag peers that repeatedly exceed the cap as misbehaving","Only raise the cap deliberately and with memory budgeting"],"tags":["network","security","payload-size","federation"],"backgroundTag":"payload-too-large","analyzedSha":"2602b642d92234c710ffbe96bfb33007d481ceab","analyzedAt":"2026-09-15T22:58:14.805Z","contentChangedAt":"2026-09-15T22:58:14.805Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}