ruvnet/ruflo · error

roomId is required

Error message

roomId is required

What it means

validateRoomId() requires a non-empty string roomId before any room-scoped federation operation proceeds. A missing, null, undefined, or empty roomId cannot identify a room on disk, so the library fails fast. This is the first of several checks (length, charset, traversal) applied to room identifiers.

Solutions

  1. Check the caller and ensure a non-empty roomId is passed (default it or reject the request earlier).
  2. Validate/skip envelopes without roomId before merging: if (!env.roomId) continue.
  3. At API boundaries, return a 400 to clients that omit roomId instead of letting it reach the sync layer.
  4. Add a runtime check at the entry point that produces the call so the failure surfaces where the data originates.

Example fix

// before
syncRoomFromPeer(base, peer, envelope.roomId); // throws when missing
// after
if (!envelope.roomId) { log.warn('envelope missing roomId'); return; }
syncRoomFromPeer(base, peer, envelope.roomId);
Defensive patterns

Strategy: validation

Validate before calling

function hasRoomId(v) { return typeof v === 'string' && v.length > 0; }
if (!hasRoomId(envelope.roomId)) throw new Error('roomId is required');

Type guard

const hasRoomId = (v: unknown): v is string => typeof v === 'string' && v.length > 0;

Try / catch

try {
  syncRoomFromPeer(basePath, peer, roomId);
} catch (e) {
  if (e.message === 'roomId is required') {
    log.warn('skipping envelope without roomId');
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling mergeEnvelopes, syncRoomFromPeer, or a server handler with roomId === '' , null, or undefined — e.g. an envelope JSON parsed from a peer line lacking a roomId field, or a request handler that never extracted the room from the URL/body.

Common situations: Malformed envelopes from a remote peer missing the roomId field; frontend sending an empty room query param; refactored code path dropping the roomId argument; a sync job iterating records where roomId is optional.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

  const next = peers.filter(p => p.nodeId !== nodeId);
  if (next.length === peers.length) return false;
  writePeers(basePath, next);
  return true;
}

export function readEnvelopes(basePath: string, roomId: string): SignedEnvelope[] {
  const p = roomLogPath(basePath, roomId);
  if (!existsSync(p)) return [];
  const out: SignedEnvelope[] = [];
  for (const line of readFileSync(p, 'utf-8').split(/\r?\n/)) {
    if (!line.trim()) continue;
    try { out.push(JSON.parse(line)); } catch { /* skip malformed */ }
  }
  return out;
}

export function validateRoomId(roomId: string): string {
  if (!roomId || typeof roomId !== 'string') throw new Error('roomId is required');
  if (roomId.length > 128) throw new Error('roomId exceeds 128 chars');
  // Also blocks path traversal: `.` is allowed but `/` segments cannot form
  // `..` without tripping the explicit check below.
  if (!ROOM_ID_RE.test(roomId)) throw new Error('roomId has invalid characters');
  if (roomId.includes('..')) throw new Error('roomId must not contain ..');
  return roomId;
}

export interface MergeResult {
  merged: number;
  skippedDuplicate: number;
  skippedUnverified: number;
  skippedOversize: number;
  skippedHopLimit: number;
}

/**
 * Union-merge verified envelopes from a peer into the local room log.

View on GitHub (pinned to 2602b642d9)