ruvnet/ruflo · error · Error
msgType must be alnum + _ - and ≤64 chars
Error message
msgType must be alnum + _ - and ≤64 chars
What it means
The agentbbs post handler validates msgType against ^[A-Za-z0-9_-]+$ with a 64-character cap — stricter than roomLabel (no dots, colons, slashes, '#', or '@'). Dotted types like 'chat.message' are therefore REJECTED despite reading naturally; use 'chat_message' instead. The strict format keeps envelope routing/dispatch unambiguous.
Solutions
- Use snake/kebab types within the charset: 'chat_message', 'task-update' — replace '.' with '_'
- Trim overlong names to ≤64 chars and prefer short vocabularies ('note', 'alert', 'assign')
- Validate at the caller with the same regex /^[A-Za-z0-9_-]+$/ and length check for an early error
Example fix
// before — dot not allowed
await callMCPTool('agentbbs_post', { roomId, msgType: 'chat.message', payload });
// after — underscore form
await callMCPTool('agentbbs_post', { roomId, msgType: 'chat_message', payload }); Defensive patterns
Strategy: validation
Validate before calling
const MSG_TYPE_RE = /^[A-Za-z0-9_-]+$/;
function normalizeMsgType(raw: string): string {
const t = raw.replace(/[.:/@#\s]+/g, '_').replace(/[^A-Za-z0-9_-]/g, '');
if (t.length === 0 || t.length > 64 || !MSG_TYPE_RE.test(t)) {
throw new Error(`cannot normalize msgType: ${raw}`);
}
return t;
} Type guard
const isValidMsgType = (v: string): boolean => /^[A-Za-z0-9_-]+$/.test(v) && v.length <= 64 && v.length > 0;
Prevention
- Standardize on snake_case msgTypes — dots, slashes, and '#' are not accepted (stricter than roomLabel)
- Keep the type vocabulary short (≤64 chars)
- Map external dotted event names to underscores at your boundary
When it happens
Trigger: Passing 'chat.message' (dot), 'user/mention' (slash), 'a b' (space), '#announce' ('#'), or any type longer than 64 chars; migrating message schemas from systems that use dotted or URI-style type names.
Common situations: Teams standardizing on namespaced dotted event names (activitystrea.ms style) hitting the charset rule; long fully-qualified type names exceeding 64 chars.
Related errors
- msgType is required
- payload must be a JSON object
- roomId may only contain [A-Za-z0-9_.\\-:/@#]
- roomLabel may only contain [A-Za-z0-9_.\\-:/@#]
- basePath contains disallowed characters
AI-assisted analysis of ruvnet/ruflo@9c61c86f06 (2026-08-18).
Data as JSON: /api/errors/46404fac50427b14.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/mcp-tools/agentbbs-tools.ts:400
},
payload: {
type: 'object',
description: 'Event-specific JSON-serializable payload.',
},
signature: {
type: 'string',
description: 'Optional Ed25519 signature over the canonical envelope bytes. Phase 1: pass-through.',
},
},
required: ['roomId', 'msgType', 'payload'],
},
handler: async (input) => {
const basePath = resolveBasePath(input.basePath as string | undefined);
const roomId = validateRoomId(String(input.roomId));
const msgType = String(input.msgType ?? '');
if (!msgType) throw new Error('msgType is required');
if (msgType.length > 64 || !/^[A-Za-z0-9_-]+$/.test(msgType)) {
throw new Error('msgType must be alnum + _ - and ≤64 chars');
}
if (typeof input.payload !== 'object' || input.payload === null) {
throw new Error('payload must be a JSON object');
}
if (!agentbbsCliAvailable()) return degradedResult('agentbbs-not-found');
ensureDir(basePath);
const logPath = roomLogPath(basePath, roomId);
const base: BbsEnvelope = {
envelopeId: base64url(randomBytes(12)),
roomId,
seq: nextSeq(logPath),
msgType,
payload: input.payload,
timestamp: new Date().toISOString(),
};
// Phase 2: sign with this host's persistent node identity so peers canView on GitHub (pinned to 9c61c86f06)