ruvnet/ruflo · error

peer response exceeds size cap

Error message

peer ${peer.nodeId} response exceeds size cap

What it means

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.

Solutions

  1. Sync more frequently so the incremental delta per sync stays under the size cap.
  2. If the peer supports query parameters, narrow the sync window (since/limit) to reduce response size.
  3. 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).
  4. Investigate the peer if the size is implausible — an oversized response may indicate a misbehaving or hostile node.

Example fix

// before
await syncRoomFromPeer(peer, roomId); // huge backlog -> size cap error
// after
for (const window of [3600, 86400, 604800]) { // grow until under cap
  try { await syncRoomFromPeer(peer, roomId, { sinceSeconds: window }); break; }
  catch (e) { if (!/size cap/.test(e.message)) throw e; }
}
Defensive patterns

Strategy: fallback

Validate before calling

// preflight: request a small window first
const probe = await fetch(syncUrl + '?since=3600');
const len = Number(probe.headers.get('content-length') ?? 0);
if (len > MAX_SYNC_RESPONSE_BYTES) console.warn('response would exceed size cap');

Type guard

function isWithinCap(text: string, cap: number): boolean { return text.length <= cap; }

Try / catch

try {
  await syncRoomFromPeer(peer, roomId);
} catch (e) {
  if (/response exceeds size cap/.test(e.message)) {
    await syncRoomFromPeer(peer, roomId, { sinceSeconds: 3600 }); // smaller delta
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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 ruvnet/ruflo@2602b642d9 (2026-09-15). Data as JSON: /api/errors/f555ab5144cc1cc9. Report an issue: GitHub.

Appendix: source

Thrown at v3/@claude-flow/cli/src/mcp-tools/agentbbs-federation.ts:394

/** Pull one room from one peer and merge what verifies. */
export async function syncRoomFromPeer(
  basePath: string,
  peer: FederationPeer,
  roomId: string,
  fetchImpl: typeof fetch = fetch,
): Promise<MergeResult & { peerNodeId: string; roomId: string }> {
  validateRoomId(roomId);
  const since = peer.lastSeq?.[roomId] ?? 0;
  const url = `${peer.url}/agentbbs/v1/rooms/${encodeURIComponent(roomId)}/envelopes?since=${since}`;

  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), SYNC_TIMEOUT_MS);
  let body: any;
  try {
    const res = await fetchImpl(url, { signal: controller.signal, headers: { accept: 'application/json' } });
    if (!res.ok) throw new Error(`peer ${peer.nodeId} returned ${res.status}`);
    const text = await res.text();
    if (text.length > MAX_SYNC_RESPONSE_BYTES) throw new Error(`peer ${peer.nodeId} response exceeds size cap`);
    body = JSON.parse(text);
  } finally {
    clearTimeout(timer);
  }

  const envelopes: SignedEnvelope[] = Array.isArray(body?.envelopes) ? body.envelopes : [];
  const merged = await mergeEnvelopes(basePath, roomId, envelopes, peer.publicKey);

  const peers = readPeers(basePath);
  const rec = peers.find(p => p.nodeId === peer.nodeId);
  if (rec) {
    rec.lastSyncedAt = new Date().toISOString();
    rec.lastSeq = rec.lastSeq ?? {};
    const maxSeq = envelopes.reduce((m, e) => Math.max(m, Number(e.seq) || 0), since);
    rec.lastSeq[roomId] = maxSeq;
    writePeers(basePath, peers);
  }
  return { ...merged, peerNodeId: peer.nodeId, roomId };

View on GitHub (pinned to 2602b642d9)