{"record":{"id":"ad42b4e4980dabe0","repo":"ruvnet/ruflo","slug":"pod-template-at-path-roomid-may-only-contain","errorCode":null,"errorMessage":"pod-template at ${path}: roomId may only contain [A-Za-z0-9_.\\-:/@#]","messagePattern":"pod-template at (.+?): roomId may only contain \\[A-Za-z0-9_\\.\\\\-:/@#\\]","errorType":"validation","errorClass":"PodTemplateValidationError","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/business-pods/pod-schema.ts","lineNumber":198,"sourceCode":" * `PodTemplateValidationError` with a JSON-pointer-style path on failure.\n *\n * Used by:\n *   - `business_pod_validate` MCP tool — returns the error verbatim\n *   - `pod-tick.mjs` — pre-flight check before any pod execution\n *   - any external schema-loader that wants typed templates\n */\nexport function validatePodTemplate(json: unknown): PodTemplate {\n  if (!isObject(json)) {\n    throw new PodTemplateValidationError('pod-template must be a JSON object', '/');\n  }\n  const name = requireString(json, 'name', '/');\n  if (!/^[a-z][a-z0-9-]*$/.test(name)) {\n    throw new PodTemplateValidationError('name must be lowercase-kebab (e.g. \"sales\")', '/');\n  }\n  const displayName = requireString(json, 'displayName', '/');\n  const roomId = requireString(json, 'roomId', '/');\n  if (!/^[A-Za-z0-9_.\\-:/@#]+$/.test(roomId)) {\n    throw new PodTemplateValidationError(\n      'roomId may only contain [A-Za-z0-9_.\\\\-:/@#]',\n      '/',\n    );\n  }\n  const agents = requireArray(json, 'agents', '/', validatePodAgent);\n  if (agents.length === 0) {\n    throw new PodTemplateValidationError('agents must have ≥1 entry', '/');\n  }\n  const allowedMcpTools = requireArray(json, 'allowedMcpTools', '/', (t, tp) => {\n    if (typeof t !== 'string' || t.length === 0) {\n      throw new PodTemplateValidationError(\n        'allowedMcpTools entries must be non-empty strings',\n        tp,\n      );\n    }\n    return t;\n  });\n  if (allowedMcpTools.length === 0) {","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/cli/src/business-pods/pod-schema.ts#L180-L216","documentation":"Thrown by validatePodTemplate() when the 'roomId' field contains characters outside the allowed set [A-Za-z0-9_.\\-:/@#]. The roomId identifies the BBS room this pod serves. Unlike 'name', it permits a broader character set including uppercase, colons, slashes, and a few symbols, but still rejects spaces, quotes, and most punctuation.","triggerScenarios":"The 'roomId' field contains a space, comma, parenthesis, brace, or any character not in [A-Za-z0-9_.\\-:/@#]. For example 'sales room', 'sales(room)', or 'sales+pipeline'.","commonSituations":"A human-readable room description was placed in roomId instead of the machine identifier; the roomId was copied from a URL with query parameters like '?' or '='.","solutions":["Strip spaces and disallowed punctuation from roomId","Use only characters in [A-Za-z0-9_.\\-:/@#] — colons and slashes are acceptable for namespace-style room IDs","If the room needs a friendly name, put it in 'displayName' instead"],"exampleFix":"// before\n{ \"roomId\": \"sales room (west)\" }\n\n// after\n{ \"roomId\": \"sales:west\" }","handlingStrategy":"validation","validationCode":"const ROOM_ID_RE = /^[A-Za-z0-9_.\\-:/@#]+$/;\nfunction isValidRoomId(id: string): boolean {\n  return ROOM_ID_RE.test(id);\n}\n\nif (!isValidRoomId(template.roomId)) {\n  console.error('roomId has invalid characters');\n}","typeGuard":"function isValidRoomId(id: string): boolean {\n  return /^[A-Za-z0-9_.\\-:/@#]+$/.test(id);\n}","tryCatchPattern":"try {\n  validatePodTemplate(json);\n} catch (e) {\n  if (e instanceof PodTemplateValidationError && e.message.includes('roomId')) {\n    // Sanitize or fix roomId characters\n  }\n}","preventionTips":["Use only [A-Za-z0-9_.\\-:/@#] characters in roomId","Put human-readable descriptions in displayName, not roomId","Avoid spaces, commas, and parentheses in roomId"],"tags":["pod-template","validation","schema","business-pods"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}