{"record":{"id":"15c8088fa2313e28","repo":"ruvnet/ruflo","slug":"payload-must-be-a-json-object","errorCode":null,"errorMessage":"payload must be a JSON object","messagePattern":"payload must be a JSON object","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/mcp-tools/agentbbs-tools.ts","lineNumber":280,"sourceCode":"          description: 'Event-specific JSON-serializable payload.',\n        },\n        signature: {\n          type: 'string',\n          description: 'Optional Ed25519 signature over the canonical envelope bytes. Phase 1: pass-through.',\n        },\n      },\n      required: ['roomId', 'msgType', 'payload'],\n    },\n    handler: async (input) => {\n      const basePath = resolveBasePath(input.basePath as string | undefined);\n      const roomId = validateRoomId(String(input.roomId));\n      const msgType = String(input.msgType ?? '');\n      if (!msgType) throw new Error('msgType is required');\n      if (msgType.length > 64 || !/^[A-Za-z0-9_-]+$/.test(msgType)) {\n        throw new Error('msgType must be alnum + _ - and ≤64 chars');\n      }\n      if (typeof input.payload !== 'object' || input.payload === null) {\n        throw new Error('payload must be a JSON object');\n      }\n\n      const api = await loadAgentbbs();\n      if (!api) return degradedResult('agentbbs-not-found');\n\n      ensureDir(basePath);\n      const logPath = roomLogPath(basePath, roomId);\n      const env: BbsEnvelope = {\n        envelopeId: base64url(randomBytes(12)),\n        roomId,\n        seq: nextSeq(logPath),\n        msgType,\n        payload: input.payload,\n        timestamp: new Date().toISOString(),\n        signature: input.signature ? String(input.signature) : undefined,\n      };\n      appendFileSync(logPath, JSON.stringify(env) + '\\n');\n","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/cli/src/mcp-tools/agentbbs-tools.ts#L262-L298","documentation":"Thrown by the federation_bbs_publish handler when input.payload is not a plain JSON object — i.e. typeof !== 'object', or it is null. Payload is wrapped into the ReplicateMessage envelope as-is and appended to the room log, so it must be a JSON-serializable record; arrays, primitives, and undefined are rejected because they break the envelope contract and the cockpit's typed dispatch.","triggerScenarios":"Passing payload as a string, number, array, or undefined; passing null explicitly; a JSON.parse(...) that returned a primitive; a serializer that returned undefined under an error path.","commonSituations":"Producer that sometimes emits a bare string instead of an object; a fixture with `payload: JSON.stringify(x)` (double-encoded); a default {} that got overwritten to null upstream.","solutions":["Always pass payload as a plain object: `payload: { detail: 'x', code: 1 }`.","If your data is a primitive, wrap it: `payload: { value: x }`.","Guard at your boundary: `if (typeof p !== 'object' || p === null) throw ...` before calling the tool."],"exampleFix":"// before\nfederation_bbs_publish({ roomId, msgType, payload: 'disk full' });\n// after\nfederation_bbs_publish({ roomId, msgType, payload: { message: 'disk full', code: 'ENOSPC' } });","handlingStrategy":"type-guard","validationCode":"function requirePayloadObject(p: unknown): Record<string, unknown> {\n  if (typeof p !== 'object' || p === null || Array.isArray(p)) {\n    throw new Error('payload must be a plain JSON object');\n  }\n  return p as Record<string, unknown>;\n}","typeGuard":"const isPlainObject = (v: unknown): v is Record<string, unknown> =>\n  typeof v === 'object' && v !== null && !Array.isArray(v);","tryCatchPattern":"null","preventionTips":["Wrap primitive payloads in an object before publish.","Double-check you are not passing JSON.stringify output as payload.","Schema-validate payload at your boundary (zod object with passthrough)."],"tags":["validation","agentbbs","federation","payload"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}