ruvnet/ruflo · error · Error
roomLabel may only contain [A-Za-z0-9_.\-:/@#]
Error message
roomLabel may only contain [A-Za-z0-9_.\-:/@#]
What it means
Thrown by validateRoomLabel() when the label is present but fails the allow-list regex `/^[A-Za-z0-9_.\-:/@#]+$/` (label exceeds 128 chars is a separate throw). The allow-list intentionally keeps `#` (rooms are conventionally `#sales`), `:` and `/` for scoping, plus alnum and a few safe symbols — anything else (spaces, commas, unicode, shell metacharacters) is rejected because the label becomes part of a filesystem room-id hash and log lines.
Source
Thrown at v3/@claude-flow/cli/src/mcp-tools/agentbbs-tools.ts:74
function degradedResult(reason: string): { success: true; degraded: true; reason: string } {
return { success: true, degraded: true, reason };
}
function resolveBasePath(input?: string): string {
const p = input && typeof input === 'string' && input.length > 0
? input
: '.agentbbs';
if (/\.\.[\\/]|\0/.test(p)) throw new Error('basePath contains disallowed characters');
const abs = isAbsolute(p) ? p : resolve(getProjectCwd(), p);
return abs;
}
function validateRoomLabel(label: string): string {
if (!label || typeof label !== 'string') throw new Error('roomLabel is required');
if (label.length > 128) throw new Error('roomLabel exceeds 128 chars');
// Rooms are conventionally `#sales`, `#finance`, etc. — keep `#` in the allow-list.
if (!/^[A-Za-z0-9_.\-:/@#]+$/.test(label)) {
throw new Error('roomLabel may only contain [A-Za-z0-9_.\\-:/@#]');
}
return label;
}
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');
if (!/^[A-Za-z0-9_.\-:/@#]+$/.test(roomId)) {
throw new Error('roomId may only contain [A-Za-z0-9_.\\-:/@#]');
}
return roomId;
}
function ensureDir(dir: string): void {
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
}
function roomIdFromLabel(label: string): string {View on GitHub (pinned to 6b01dc5a68)
Solutions
- Restrict labels to the documented set: alphanumerics and `_ . - : / @ #`.
- Sanitize/normalize the label upstream: trim whitespace, strip disallowed chars, or slugify.
- If you need richer identifiers, encode them inside payload rather than the room label.
Example fix
// before
federation_bbs_register({ roomLabel: '#sales team!' });
// after
federation_bbs_register({ roomLabel: '#sales-team' }); Defensive patterns
Strategy: validation
Validate before calling
const ROOM_LABEL_RE = /^[A-Za-z0-9_.\-:/@#]+$/;
function normalizeRoomLabel(label: string): string {
const v = label.trim();
if (!ROOM_LABEL_RE.test(v)) throw new Error('roomLabel has disallowed chars');
return v;
} Type guard
const isRoomLabel = (v: string): boolean => /^[A-Za-z0-9_.\-:/@#]+$/.test(v);
Try / catch
null
Prevention
- Trim and slugify free-form input before constructing room labels.
- Reject smart quotes and unicode whitespace from copy-paste upstream.
- Document the allow-list for your integrators so they do not guess.
When it happens
Trigger: Label contains a space (`'#sales team'`), a comma, shell metacharacters (`#x;rm`), unicode characters, or punctuation not in the allow-list (`#x!`, `#x*`).
Common situations: Free-form user input piped straight into roomLabel; a copy-paste that introduced a trailing space or smart quote; a templating layer that joined labels with a disallowed separator.
Related errors
- roomId may only contain [A-Za-z0-9_.\-:/@#]
- roomLabel is required
- roomId is required
- msgType is required
- msgType must be alnum + _ - and ≤64 chars
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/e818eb8e0ffd5e2b.
Report an issue: GitHub.