ruvnet/ruflo · error · PodTemplateValidationError

pod-template at ${path}: roomId may only contain [A-Za-z0-9_

Error message

pod-template at ${path}: roomId may only contain [A-Za-z0-9_.\-:/@#]

What it means

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.

Source

Thrown at v3/@claude-flow/cli/src/business-pods/pod-schema.ts:198

 * `PodTemplateValidationError` with a JSON-pointer-style path on failure.
 *
 * Used by:
 *   - `business_pod_validate` MCP tool — returns the error verbatim
 *   - `pod-tick.mjs` — pre-flight check before any pod execution
 *   - any external schema-loader that wants typed templates
 */
export function validatePodTemplate(json: unknown): PodTemplate {
  if (!isObject(json)) {
    throw new PodTemplateValidationError('pod-template must be a JSON object', '/');
  }
  const name = requireString(json, 'name', '/');
  if (!/^[a-z][a-z0-9-]*$/.test(name)) {
    throw new PodTemplateValidationError('name must be lowercase-kebab (e.g. "sales")', '/');
  }
  const displayName = requireString(json, 'displayName', '/');
  const roomId = requireString(json, 'roomId', '/');
  if (!/^[A-Za-z0-9_.\-:/@#]+$/.test(roomId)) {
    throw new PodTemplateValidationError(
      'roomId may only contain [A-Za-z0-9_.\\-:/@#]',
      '/',
    );
  }
  const agents = requireArray(json, 'agents', '/', validatePodAgent);
  if (agents.length === 0) {
    throw new PodTemplateValidationError('agents must have ≥1 entry', '/');
  }
  const allowedMcpTools = requireArray(json, 'allowedMcpTools', '/', (t, tp) => {
    if (typeof t !== 'string' || t.length === 0) {
      throw new PodTemplateValidationError(
        'allowedMcpTools entries must be non-empty strings',
        tp,
      );
    }
    return t;
  });
  if (allowedMcpTools.length === 0) {

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Strip spaces and disallowed punctuation from roomId
  2. Use only characters in [A-Za-z0-9_.\-:/@#] — colons and slashes are acceptable for namespace-style room IDs
  3. If the room needs a friendly name, put it in 'displayName' instead

Example fix

// before
{ "roomId": "sales room (west)" }

// after
{ "roomId": "sales:west" }
Defensive patterns

Strategy: validation

Validate before calling

const ROOM_ID_RE = /^[A-Za-z0-9_.\-:/@#]+$/;
function isValidRoomId(id: string): boolean {
  return ROOM_ID_RE.test(id);
}

if (!isValidRoomId(template.roomId)) {
  console.error('roomId has invalid characters');
}

Type guard

function isValidRoomId(id: string): boolean {
  return /^[A-Za-z0-9_.\-:/@#]+$/.test(id);
}

Try / catch

try {
  validatePodTemplate(json);
} catch (e) {
  if (e instanceof PodTemplateValidationError && e.message.includes('roomId')) {
    // Sanitize or fix roomId characters
  }
}

Prevention

When it happens

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

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

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/ad42b4e4980dabe0. Report an issue: GitHub.