{"record":{"id":"de91cf8e42a2099d","repo":"gitroomhq/postiz-app","slug":"integration-not-allowed","errorCode":null,"errorMessage":"Integration not allowed","messagePattern":"Integration not allowed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/backend/src/api/routes/enterprise.controller.ts","lineNumber":71,"sourceCode":"        webhookUrl: string;\n      };\n\n      if (!load || !load.redirectUrl || !load.apiKey || !load.provider) {\n        return;\n      }\n\n      const org = await this._organizationService.getOrgByApiKey(load.apiKey);\n\n      if (!org) {\n        throw new Error('Organization not found');\n      }\n\n      if (\n        !this._integrationManager\n          .getAllowedSocialsIntegrations()\n          .includes(load.provider)\n      ) {\n        throw new Error('Integration not allowed');\n      }\n\n      const integrationProvider = this._integrationManager.getSocialIntegration(\n        load.provider\n      );\n\n      const { codeVerifier, state, url } =\n        await integrationProvider.generateAuthUrl();\n\n      if (load.refreshId) {\n        await ioRedis.set(`refresh:${state}`, load.refreshId, 'EX', 3600);\n      }\n\n      await ioRedis.set(`webhookUrl:${state}`, load.webhookUrl, 'EX', 3600);\n      await ioRedis.set(`redirect:${state}`, load.redirectUrl, 'EX', 3600);\n      await ioRedis.set(`organization:${state}`, org.id, 'EX', 3600);\n      await ioRedis.set(`login:${state}`, codeVerifier, 'EX', 3600);\n","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/gitroomhq/postiz-app/blob/0f1647f7491a217d43eb5ae7a480484bdf0aff3e/apps/backend/src/api/routes/enterprise.controller.ts#L53-L89","documentation":"POST /integration/:id/additional-settings expects the additionalSettings body field to be a string (providers store settings as a serialized string). If the client sends an object, array, number, or omits the field, the typeof check fails and Error('Invalid body') is thrown (500 to the client).","triggerScenarios":"Sending { additionalSettings: { foo: true } } or any non-string JSON value to the endpoint; sending an empty body.","commonSituations":"Frontend code JSON.stringifying in one place but not another; client sending a structured object assuming the API parses it; API consumers testing with curl omitting Content-Type leading to undefined body.","solutions":["Serialize the settings client-side: send JSON.stringify(settings) as additionalSettings","Ensure the request has Content-Type: application/json and the field is present","Add request validation (class-validator DTO) so this returns 400 with a clear message"],"exampleFix":"// before\nawait fetch(`/integration/${id}/additional-settings`, {\n  body: JSON.stringify({ additionalSettings: settings })\n});\n// after\nawait fetch(`/integration/${id}/additional-settings`, {\n  body: JSON.stringify({ additionalSettings: JSON.stringify(settings) })\n});","handlingStrategy":"validation","validationCode":"if (typeof additionalSettings !== 'string') {\n  payload.additionalSettings = JSON.stringify(additionalSettings);\n}","typeGuard":"const isSettingsString = (v: unknown): v is string => typeof v === 'string';","tryCatchPattern":"try { await updateSettings(id, settings); } catch (e) { if (e.message === 'Invalid body') retryWithSerialized(settings); else throw e; }","preventionTips":["Always JSON.stringify structured settings before sending","Centralize serialization in one API-client helper"],"tags":["validation","integrations","request-body"],"backgroundTag":"schema-validation-failed","analyzedSha":"0f1647f7491a217d43eb5ae7a480484bdf0aff3e","analyzedAt":"2026-08-27T12:09:55.020Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}