{"record":{"id":"b5f900cf6e2bdf04","repo":"ruvnet/ruflo","slug":"roomid-may-only-contain-a-za-z0-9","errorCode":null,"errorMessage":"roomId may only contain [A-Za-z0-9_.\\-:/@#]","messagePattern":"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/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/business-pods/pod-schema.ts#L180-L216","documentation":"The top-level roomId must match /^[A-Za-z0-9_.\\-:/@#]+$/: only letters, digits, underscore, dot, hyphen, colon, slash, at-sign, and hash. Spaces, commas, percent signs, pluses, quotes, and any non-ASCII characters are rejected. This charset matches the room/namespace identifiers used by the coordination transport, where other characters would break routing or shell safety.","triggerScenarios":"A template with roomId containing spaces (\"team sales\"), percent-encoded characters (\"team%20sales\"), a plus sign from URL encoding, or emoji/unicode pasted from a chat app.","commonSituations":"Pasting a chat room title instead of its ID/alias; copy-paste introducing a trailing space or smart quote; using URL-encoded forms of the room identifier.","solutions":["Replace spaces with hyphens or use the canonical room ID (\"team-sales\" or \"#team-sales:example.org\")","Trim the value and re-check for invisible characters (smart quotes, non-breaking spaces) — retype it if unsure","URL-decode the value first if it arrived percent-encoded, then confirm every remaining char is in the allowed set"],"exampleFix":"// before\n\"roomId\": \"team sales room\"\n// after\n\"roomId\": \"team-sales\"","handlingStrategy":"validation","validationCode":"const ROOM_ID_RE = /^[A-Za-z0-9_.\\-:/@#]+$/;\nif (!ROOM_ID_RE.test(template.roomId)) {\n  template.roomId = template.roomId.trim().replace(/\\s+/g, '-');\n}","typeGuard":"function isSafeRoomId(v: unknown): v is string {\n  return typeof v === 'string' && /^[A-Za-z0-9_.\\-:/@#]+$/.test(v);\n}","tryCatchPattern":"try { validatePodTemplate(json); } catch (err) {\n  if (err instanceof PodTemplateValidationError && /roomId/.test(err.message)) {\n    // sanitize: decodeURIComponent first, then replace disallowed chars\n  }\n}","preventionTips":["Store the canonical room ID in your inventory, never paste display titles","URL-decode identifiers that traveled through query strings before embedding them"],"tags":["schema-validation","business-pods","room-id","charset","configuration"],"backgroundTag":"schema-validation-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}