{"record":{"id":"f6ff6274d060ccb7","repo":"RocketChat/Rocket.Chat","slug":"integration-payload-must-be-a-json-object-not-an","errorCode":null,"errorMessage":"Integration payload must be a JSON object, not an array or primitive","messagePattern":"Integration payload must be a JSON object, not an array or primitive","errorType":"http","errorClass":"Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/server/api/webhooks.ts","lineNumber":141,"sourceCode":" * with Content-Type: application/x-www-form-urlencoded (e.g. `payload={\"text\":\"hello\"}`).\n * This function unwraps it so integrations receive the parsed JSON directly.\n */\nfunction getBodyParams(bodyParams: unknown, request: Request): Record<string, unknown> {\n\tif (!isPlainObject(bodyParams)) {\n\t\treturn {};\n\t}\n\n\tif (\n\t\trequest.headers.get('content-type')?.startsWith('application/x-www-form-urlencoded') &&\n\t\tObject.keys(bodyParams).length === 1 &&\n\t\ttypeof bodyParams.payload === 'string'\n\t) {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(bodyParams.payload);\n\n\t\t\t// Valid JSON must be an object, not an array or primitive\n\t\t\tif (!isPlainObject(parsed)) {\n\t\t\t\tthrow new Error('Integration payload must be a JSON object, not an array or primitive');\n\t\t\t}\n\n\t\t\treturn parsed;\n\t\t} catch (err) {\n\t\t\t// Invalid JSON -> return original bodyParams (backward compatibility)\n\t\t\tif (err instanceof SyntaxError) {\n\t\t\t\treturn bodyParams;\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\treturn bodyParams;\n}\n\nasync function executeIntegrationRest(\n\tthis: IntegrationThis,\n): Promise<","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/webhooks.ts#L123-L159","documentation":"Thrown by getBodyParams() in the incoming-webhook body parser when the request is form-urlencoded with a single 'payload' field, the payload parses as valid JSON, but the parsed value is not a plain object (it is an array or a primitive like a string/number/boolean). Slack/GitHub-style webhooks wrap a JSON object in payload; this guard rejects malformed integrations that wrap non-object JSON.","triggerScenarios":"POST to a webhook URL with Content-Type application/x-www-form-urlencoded and body payload=[1,2,3] or payload=\"hello\" or payload=42. The JSON is syntactically valid but not an object, so the parser refuses to substitute it for the body params.","commonSituations":"An integration forwards an array-wrapped event instead of an object. A misconfigured upstream service sends payload=<string>. A migration tool emits top-level arrays.","solutions":["Ensure the upstream sends payload as a JSON object literal, e.g. payload={\"text\":\"hello\"}.","If the upstream legitimately sends an array, wrap it in an object before forwarding: {\"events\":[...]}","Switch the Content-Type to application/json and POST the object directly if the wrapper is not required."],"exampleFix":"// before - upstream sends\n// Content-Type: application/x-www-form-urlencoded\n// payload=[{\"text\":\"hi\"}]\n\n// after\n// Content-Type: application/x-www-form-urlencoded\n// payload={\"items\":[{\"text\":\"hi\"}]}","handlingStrategy":"type-guard","validationCode":"function isPlainObject(v) { return typeof v === 'object' && v !== null && !Array.isArray(v); }\nif (typeof bodyParams.payload === 'string') {\n  const parsed = JSON.parse(bodyParams.payload);\n  if (!isPlainObject(parsed)) throw new ClientError('payload must be object');\n}","typeGuard":"function isPlainObject(v) {\n  if (v === null || typeof v !== 'object') return false;\n  const proto = Object.getPrototypeOf(v);\n  return proto === Object.prototype || proto === null;\n}","tryCatchPattern":null,"preventionTips":["Configure the upstream to send payload=<object> or use application/json directly.","Wrap array data in {\"items\":[...]} before forwarding.","Test the webhook payload shape against isPlainObject before going live."],"tags":["api","integrations","webhooks","json","validation"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}