{"record":{"id":"87fca01bd3f058fa","repo":"RocketChat/Rocket.Chat","slug":"error-inserting-integration","errorCode":null,"errorMessage":"Error inserting integration","messagePattern":"Error inserting integration","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/integrations/incoming/addIncomingIntegration.ts","lineNumber":177,"sourceCode":"\n\t\tif (\n\t\t\t!(await hasAllPermissionAsync(userId, ['manage-incoming-integrations', 'manage-own-incoming-integrations'])) &&\n\t\t\t!(await Subscriptions.findOneByRoomIdAndUserId(record._id, userId, { projection: { _id: 1 } }))\n\t\t) {\n\t\t\tthrow new Meteor.Error('error-invalid-channel', 'Invalid Channel', {\n\t\t\t\tmethod: 'addIncomingIntegration',\n\t\t\t});\n\t\t}\n\t}\n\n\tconst strippedIntegrationData = removeEmpty(integrationData);\n\n\tconst { insertedId } = await Integrations.insertOne(strippedIntegrationData);\n\n\tconst integrationStored = await Integrations.findOne({ _id: insertedId });\n\n\tif (!integrationStored) {\n\t\tthrow new Error('Error inserting integration');\n\t}\n\tvoid notifyOnIntegrationChanged({ ...integrationStored, _id: insertedId }, 'inserted');\n\n\treturn integrationStored as IIncomingIntegration;\n};\n\nMeteor.methods<ServerMethods>({\n\tasync addIncomingIntegration(integration: INewIncomingIntegration): Promise<IIncomingIntegration> {\n\t\tmethodDeprecationLogger.method('addIncomingIntegration', '9.0.0', '/v1/integrations.create');\n\t\tconst { userId } = this;\n\n\t\tif (!userId) {\n\t\t\tthrow new Meteor.Error('invalid-user', 'Invalid User', {\n\t\t\t\tmethod: 'addIncomingIntegration',\n\t\t\t});\n\t\t}\n\n\t\treturn addIncomingIntegration(userId, integration);","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/integrations/incoming/addIncomingIntegration.ts#L159-L195","documentation":"A plain Error (not Meteor.Error, no error code) thrown when Integrations.findOne({ _id: insertedId }) returns null immediately after a successful insertOne. It signals a read-after-write inconsistency: the insert reported success but the follow-up read cannot find the document. Because it is not a Meteor.Error, DDP clients in production receive the sanitized 'Internal server error [500]'; the real message appears only in server logs.","triggerScenarios":"MongoDB reads routed to a secondary with replication lag (readPreference secondaryPreferred/nearest); an external watcher/trigger deleting the integration between insert and read; a flaky proxy or mongos dropping the read. Extremely rare on a healthy single-node deployment.","commonSituations":"Self-hosted replica sets with misconfigured read preference; aggressive custom cleanup jobs on the integrations collection; middleware that audits and prunes new documents.","solutions":["Retry the call once - but first check whether the first attempt actually inserted a record (list integrations) to avoid duplicates","Check replica set health, oplog, and the driver's readPreference; route reads to primary for this path","Look for custom observers/triggers on the integrations collection that delete on insert","If it persists on a stock setup, collect server logs and open a Rocket.Chat core issue"],"exampleFix":"// before: single attempt\nconst integration = await Meteor.callAsync('addIncomingIntegration', payload);\n// after: verify-then-retry on the rare read-after-write miss\nlet integration;\nfor (let attempt = 0; attempt < 2; attempt++) {\n  try {\n    integration = await Meteor.callAsync('addIncomingIntegration', payload);\n    break;\n  } catch (e) {\n    if (attempt === 1 || !(e instanceof Meteor.Error)) throw e; // sanitized 500 lands here, real message is in server logs\n    const existing = await Meteor.callAsync('listIncomingIntegrations');\n    if (existing.integrations?.some((i) => i.name === payload.name)) break; // insert actually succeeded\n  }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"const createWithRetry = async (integration, attempts = 2) => {\n  for (let i = 0; i < attempts; i++) {\n    try { return await Meteor.callAsync('addIncomingIntegration', integration); }\n    catch (err) {\n      if (i === attempts - 1 || err instanceof Meteor.Error) throw err; // sanitized 500 (non Meteor.Error) -> retry once\n      const list = await Meteor.callAsync('listIncomingIntegrations');\n      if (list.integrations?.some((x) => x.name === integration.name)) return null; // first insert actually landed\n    }\n  }\n};","preventionTips":["Keep MongoDB reads on primary for admin flows","Monitor replica set oplog lag","Deduplicate by name when retrying creation flows"],"tags":["rocket-chat","incoming-integration","database-consistency","meteor-method"],"backgroundTag":"database-write-failed","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}