{"record":{"id":"d7ae3af7d5acba2d","repo":"ruvnet/ruflo","slug":"roomlabel-is-required","errorCode":null,"errorMessage":"roomLabel is required","messagePattern":"roomLabel is required","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/mcp-tools/agentbbs-tools.ts","lineNumber":70,"sourceCode":"    throw err;\n  }\n}\n\nfunction degradedResult(reason: string): { success: true; degraded: true; reason: string } {\n  return { success: true, degraded: true, reason };\n}\n\nfunction resolveBasePath(input?: string): string {\n  const p = input && typeof input === 'string' && input.length > 0\n    ? input\n    : '.agentbbs';\n  if (/\\.\\.[\\\\/]|\\0/.test(p)) throw new Error('basePath contains disallowed characters');\n  const abs = isAbsolute(p) ? p : resolve(getProjectCwd(), p);\n  return abs;\n}\n\nfunction validateRoomLabel(label: string): string {\n  if (!label || typeof label !== 'string') throw new Error('roomLabel is required');\n  if (label.length > 128) throw new Error('roomLabel exceeds 128 chars');\n  // Rooms are conventionally `#sales`, `#finance`, etc. — keep `#` in the allow-list.\n  if (!/^[A-Za-z0-9_.\\-:/@#]+$/.test(label)) {\n    throw new Error('roomLabel may only contain [A-Za-z0-9_.\\\\-:/@#]');\n  }\n  return label;\n}\n\nfunction validateRoomId(roomId: string): string {\n  if (!roomId || typeof roomId !== 'string') throw new Error('roomId is required');\n  if (roomId.length > 128) throw new Error('roomId exceeds 128 chars');\n  if (!/^[A-Za-z0-9_.\\-:/@#]+$/.test(roomId)) {\n    throw new Error('roomId may only contain [A-Za-z0-9_.\\\\-:/@#]');\n  }\n  return roomId;\n}\n\nfunction ensureDir(dir: string): void {","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/cli/src/mcp-tools/agentbbs-tools.ts#L52-L88","documentation":"Thrown by validateRoomLabel() when the supplied label is falsy, not a string, or empty. roomLabel is the human-facing room identifier (conventionally `#sales`, `#finance`) required by federation_bbs_register before it derives a stable roomId. The guard ensures a caller cannot register an anonymous room.","triggerScenarios":"Calling federation_bbs_register with roomLabel omitted, set to '', null, undefined, or a non-string (number/object); destructuring input where the field name was misspelled (e.g. `label` instead of `roomLabel`).","commonSituations":"Schema/client sent the field under a different key; integration test fixture missing the field; a runtime where roomLabel is conditionally set and the branch hit the falsy path.","solutions":["Always supply roomLabel as a non-empty string (e.g. `#sales`).","Validate at the API boundary in your caller before invoking the tool.","If the field is genuinely optional in your pipeline, default it to a deterministic value rather than leaving it empty."],"exampleFix":"// before — field omitted\nfederation_bbs_register({ roomIdHint: 'x' }); // throws: roomLabel is required\n// after\nfederation_bbs_register({ roomLabel: '#sales' });","handlingStrategy":"validation","validationCode":"function requireRoomLabel(label: unknown): string {\n  if (typeof label !== 'string' || label.length === 0) {\n    throw new Error('roomLabel must be a non-empty string');\n  }\n  return label;\n}","typeGuard":"const isNonEmptyString = (v: unknown): v is string => typeof v === 'string' && v.length > 0;","tryCatchPattern":"null","preventionTips":["Define a shared Zod/schema for the agentbbs tool inputs at your boundary.","Unit-test the missing-field path so it fails at your layer, not inside the tool.","Thread the register result fields by name to avoid typos."],"tags":["validation","agentbbs","federation","required-field"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}