{"record":{"id":"9e4e430a49d11d3b","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-integration-9e4e43","errorCode":"error-invalid-integration","errorMessage":"Invalid integration","messagePattern":"Invalid integration","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/integrations/outgoing/deleteOutgoingIntegration.ts","lineNumber":38,"sourceCode":"\t\t});\n\t}\n\n\tconst canManageAllIntegrations = await hasPermissionAsync(userId, 'manage-outgoing-integrations');\n\tconst canManageOwnIntegrations = !canManageAllIntegrations && (await hasPermissionAsync(userId, 'manage-own-outgoing-integrations'));\n\n\tif (!canManageAllIntegrations && !canManageOwnIntegrations) {\n\t\tthrow new Meteor.Error('not_authorized', 'Unauthorized', {\n\t\t\tmethod: 'deleteOutgoingIntegration',\n\t\t});\n\t}\n\n\tconst integration = await Integrations.removeByIdAndCreatedByIfExists({\n\t\t_id: integrationId,\n\t\t...(canManageOwnIntegrations && { createdBy: userId }),\n\t});\n\n\tif (!integration) {\n\t\tthrow new Meteor.Error('error-invalid-integration', 'Invalid integration', {\n\t\t\tmethod: 'deleteOutgoingIntegration',\n\t\t});\n\t}\n\n\t// Don't sending to IntegrationHistory listener since it don't waits for 'removed' events.\n\tawait IntegrationHistory.removeByIntegrationId(integrationId);\n\tvoid notifyOnIntegrationChanged(integration, 'removed');\n};\n\nMeteor.methods<ServerMethods>({\n\tasync deleteOutgoingIntegration(integrationId) {\n\t\tmethodDeprecationLogger.method('deleteOutgoingIntegration', '9.0.0', '/v1/integrations.remove');\n\t\tconst userId = Meteor.userId();\n\t\tif (!userId) {\n\t\t\tthrow new Meteor.Error('not_authorized', 'Unauthorized', {\n\t\t\t\tmethod: 'deleteOutgoingIntegration',\n\t\t\t});\n\t\t}","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/integrations/outgoing/deleteOutgoingIntegration.ts#L20-L56","documentation":"Thrown after the permission checks pass, when Integrations.removeByIdAndCreatedByIfExists({_id, [createdBy: userId]}) modifies nothing and returns null. The integration id does not exist — or, for callers holding only manage-own-outgoing-integrations, it exists but was created by someone else, because the createdBy filter silently excludes it.","triggerScenarios":"Passing a wrong or stale integrationId; double-delete races where another admin already removed it; owning only manage-own permissions while deleting an integration another user created.","commonSituations":"Admin UI holding a stale integration list after concurrent changes; users pasting integration ids they do not own.","solutions":["Confirm the integration still exists via GET /v1/integrations.list (type webhook-outgoing) and copy the exact _id","If you hold only manage-own permissions, verify the integration's _createdBy._id is you — otherwise ask an admin to delete it","Refresh the integration list in the UI and retry with the current id"],"exampleFix":"// before\nawait Meteor.callAsync('deleteOutgoingIntegration', integrationId);\n\n// after: verify existence and ownership first\nconst res = await fetch('/api/v1/integrations.list?type=webhook-outgoing', { headers });\nconst { integrations } = await res.json();\nconst target = integrations.find((i) => i._id === integrationId);\nif (!target) throw new Error('Integration not found — refresh the list');\nawait Meteor.callAsync('deleteOutgoingIntegration', integrationId);","handlingStrategy":"validation","validationCode":"// confirm the record exists (and is yours, if you only hold manage-own)\nconst res = await fetch('/api/v1/integrations.list?type=webhook-outgoing', { headers });\nconst { integrations } = await res.json();\nconst target = integrations.find((i) => i._id === integrationId);\nif (!target) throw new Error('Integration not found');\nif (!canManageAll && target._createdBy?._id !== uid) throw new Error('Not your integration');","typeGuard":"const isDeletableIntegration = (\n  i: IIntegration | null | undefined,\n  uid: string,\n  manageAll: boolean,\n): i is IIntegration => !!i && (manageAll || i._createdBy?._id === uid);","tryCatchPattern":"try {\n  await Meteor.callAsync('deleteOutgoingIntegration', id);\n} catch (err) {\n  if (err instanceof Meteor.Error && err.error === 'error-invalid-integration') {\n    // id is gone or not owned: refresh the list and reconcile local state; do not retry\n    return;\n  }\n  throw err;\n}","preventionTips":["Always delete from a freshly loaded integration list","With manage-own permissions, only show integrations created by the current user","Treat repeat failures as already-deleted and sync your UI state"],"tags":["integrations","not-found","meteor-methods"],"backgroundTag":"resource-not-found","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}