RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-integration

error-invalid-integration

Error message

Invalid integration

What it means

Thrown by deleteIncomingIntegration when Integrations.removeByIdAndCreatedByIfExists returns null: nothing was deleted. Two distinct causes: (a) no integration with that _id exists, or (b) the caller only holds 'manage-own-incoming-integrations' and the query was scoped with createdBy: userId, so an existing integration created by someone else is invisible to the delete.

Source

Thrown at apps/meteor/server/meteor-methods/integrations/incoming/deleteIncomingIntegration.ts:33

export const deleteIncomingIntegration = async (integrationId: string, userId: string): Promise<void> => {
	const canManageAllIntegrations = !!userId && (await hasPermissionAsync(userId, 'manage-incoming-integrations'));
	const canManageOwnIntegrations =
		!canManageAllIntegrations && !!userId && (await hasPermissionAsync(userId, 'manage-own-incoming-integrations'));

	if (!canManageAllIntegrations && !canManageOwnIntegrations) {
		throw new Meteor.Error('not_authorized', 'Unauthorized', {
			method: 'deleteIncomingIntegration',
		});
	}

	const integration = await Integrations.removeByIdAndCreatedByIfExists({
		_id: integrationId,
		...(canManageOwnIntegrations && { createdBy: userId }),
	});

	if (!integration) {
		throw new Meteor.Error('error-invalid-integration', 'Invalid integration', {
			method: 'deleteIncomingIntegration',
		});
	}

	void notifyOnIntegrationChanged(integration, 'removed');
};

Meteor.methods<ServerMethods>({
	async deleteIncomingIntegration(integrationId) {
		methodDeprecationLogger.method('deleteIncomingIntegration', '9.0.0', '/v1/integrations.remove');
		const userId = Meteor.userId();
		if (!userId) {
			throw new Meteor.Error('not_authorized', 'Unauthorized', {
				method: 'deleteIncomingIntegration',
			});
		}

		await deleteIncomingIntegration(integrationId, userId);

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Verify the exact integrationId from the integrations admin screen or GET /api/v1/integrations.list before deleting
  2. If you hold only manage-own, remember you can delete only integrations you created; ask an admin (who has manage-incoming-integrations) for others
  3. Treat the error as benign if the goal was removal - confirm via the list endpoint that it is already gone

Example fix

// before
await Meteor.callAsync('deleteIncomingIntegration', 'wrongOrStaleId');
// after
const { integrations } = await fetch(`${root}/api/v1/integrations.list`, { headers: authHeaders }).then(r => r.json());
const target = integrations.find((i) => i._id === integrationId);
if (target) await Meteor.callAsync('deleteIncomingIntegration', target._id); // no-op if already removed
Defensive patterns

Strategy: validation

Validate before calling

const { integrations } = await fetch(`${root}/api/v1/integrations.list`, { headers: authHeaders }).then((r) => r.json());
const owned = integrations.filter((i) => i.type === 'webhook-incoming'); // manage-own callers only see their own anyway
if (!owned.some((i) => i._id === integrationId)) return; // already gone or not yours
await Meteor.callAsync('deleteIncomingIntegration', integrationId);

Try / catch

try {
  await Meteor.callAsync('deleteIncomingIntegration', integrationId);
} catch (err) {
  if (err instanceof Meteor.Error && err.error === 'error-invalid-integration') { /* treat as already deleted; refresh list */ }
}

Prevention

When it happens

Trigger: Passing a wrong, clipped, or already-deleted integrationId; double-submitting a delete (first succeeds, second fails); a manage-own user deleting a colleague's integration.

Common situations: Stale row in a custom integrations list after another admin already removed it; ids copied with whitespace; team shares one workspace but each member owns their own webhooks.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/89e5c60b61ed10fd. Report an issue: GitHub.