{"record":{"id":"6739b112f5faa6ea","repo":"ruvnet/ruflo","slug":"peer-peer-nodeid-returned-res-status","errorCode":null,"errorMessage":"peer ${peer.nodeId} returned ${res.status}","messagePattern":"peer (.+?) returned (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/mcp-tools/agentbbs-federation.ts","lineNumber":392,"sourceCode":"}\n\n/** 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);","sourceCodeStart":374,"sourceCodeEnd":410,"githubUrl":"https://github.com/ruvnet/ruflo/blob/2602b642d92234c710ffbe96bfb33007d481ceab/v3/@claude-flow/cli/src/mcp-tools/agentbbs-federation.ts#L374-L410","documentation":"syncRoomFromPeer fetches envelopes from a federation peer over HTTP; if the response status is not OK (res.ok false), it throws an error embedding the peer's node ID and HTTP status code. This surfaces non-2xx peer responses (404, 500, 429, etc.) as a uniform sync failure.","triggerScenarios":"Calling syncRoomFromPeer (directly or via 'r'/'second'/agentbbsTools) when the peer's sync endpoint returns a non-2xx status — peer not running, wrong URL/port, room missing on peer, or peer erroring under load.","commonSituations":"Peer node restarted or unreachable at the configured URL; room not yet created on the seconding peer (404); peer rate-limiting sync requests (429); transient 502/503 from a reverse proxy.","solutions":["Check the HTTP status in the message and the peer's URL/port configuration to make sure it points at the running peer's sync endpoint.","Retry the sync after a short backoff for transient statuses (502/503/504); respect 429 Retry-After.","Verify the room exists on the peer (create/join it there) if the status is 404.","Check the peer's logs around the request time to diagnose 5xx server-side failures."],"exampleFix":"// before\nawait syncRoomFromPeer(peer, roomId); // throws on 500\n// after\ntry {\n  await syncRoomFromPeer(peer, roomId);\n} catch (e) {\n  if (/returned (502|503|504|429)/.test(e.message)) {\n    await delay(backoff);\n    await syncRoomFromPeer(peer, roomId);\n  } else throw e;\n}","handlingStrategy":"retry","validationCode":"// preflight\nconst res = await fetch(peerSyncUrl, { method: 'HEAD' });\nif (!res.ok) console.warn(`peer unreachable, status ${res.status}`);","typeGuard":"function isOkStatus(status: number): boolean { return status >= 200 && status < 300; }","tryCatchPattern":"try {\n  await syncRoomFromPeer(peer, roomId);\n} catch (e) {\n  const m = /returned (\\d{3})/.exec(e.message);\n  const status = m ? Number(m[1]) : 0;\n  if ([429, 502, 503, 504].includes(status)) {\n    await new Promise(r => setTimeout(r, backoff));\n    return syncRoomFromPeer(peer, roomId);\n  }\n  throw e;\n}","preventionTips":["Health-check peers before syncing","Use exponential backoff with jitter for retries","Alert on persistent 5xx from a peer","Keep peer URLs in config and verify after peer restarts"],"tags":["http","network","federation","peer-sync"],"backgroundTag":"http-error-response","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"}