ruvnet/ruflo · error

peer returned

Error message

peer ${peer.nodeId} returned ${res.status}

What it means

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.

Solutions

  1. 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.
  2. Retry the sync after a short backoff for transient statuses (502/503/504); respect 429 Retry-After.
  3. Verify the room exists on the peer (create/join it there) if the status is 404.
  4. Check the peer's logs around the request time to diagnose 5xx server-side failures.

Example fix

// before
await syncRoomFromPeer(peer, roomId); // throws on 500
// after
try {
  await syncRoomFromPeer(peer, roomId);
} catch (e) {
  if (/returned (502|503|504|429)/.test(e.message)) {
    await delay(backoff);
    await syncRoomFromPeer(peer, roomId);
  } else throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

// preflight
const res = await fetch(peerSyncUrl, { method: 'HEAD' });
if (!res.ok) console.warn(`peer unreachable, status ${res.status}`);

Type guard

function isOkStatus(status: number): boolean { return status >= 200 && status < 300; }

Try / catch

try {
  await syncRoomFromPeer(peer, roomId);
} catch (e) {
  const m = /returned (\d{3})/.exec(e.message);
  const status = m ? Number(m[1]) : 0;
  if ([429, 502, 503, 504].includes(status)) {
    await new Promise(r => setTimeout(r, backoff));
    return syncRoomFromPeer(peer, roomId);
  }
  throw e;
}

Prevention

When it happens

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

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

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of ruvnet/ruflo@2602b642d9 (2026-09-15). Data as JSON: /api/errors/6739b112f5faa6ea. Report an issue: GitHub.

Appendix: source

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

}

/** 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);

View on GitHub (pinned to 2602b642d9)