RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-integration

error-invalid-integration

Error message

Invalid integration

What it means

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.

Source

Thrown at apps/meteor/server/meteor-methods/integrations/outgoing/deleteOutgoingIntegration.ts:38

		});
	}

	const canManageAllIntegrations = await hasPermissionAsync(userId, 'manage-outgoing-integrations');
	const canManageOwnIntegrations = !canManageAllIntegrations && (await hasPermissionAsync(userId, 'manage-own-outgoing-integrations'));

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

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

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

	// Don't sending to IntegrationHistory listener since it don't waits for 'removed' events.
	await IntegrationHistory.removeByIntegrationId(integrationId);
	void notifyOnIntegrationChanged(integration, 'removed');
};

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

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Confirm the integration still exists via GET /v1/integrations.list (type webhook-outgoing) and copy the exact _id
  2. If you hold only manage-own permissions, verify the integration's _createdBy._id is you — otherwise ask an admin to delete it
  3. Refresh the integration list in the UI and retry with the current id

Example fix

// before
await Meteor.callAsync('deleteOutgoingIntegration', integrationId);

// after: verify existence and ownership first
const res = await fetch('/api/v1/integrations.list?type=webhook-outgoing', { headers });
const { integrations } = await res.json();
const target = integrations.find((i) => i._id === integrationId);
if (!target) throw new Error('Integration not found — refresh the list');
await Meteor.callAsync('deleteOutgoingIntegration', integrationId);
Defensive patterns

Strategy: validation

Validate before calling

// confirm the record exists (and is yours, if you only hold manage-own)
const res = await fetch('/api/v1/integrations.list?type=webhook-outgoing', { headers });
const { integrations } = await res.json();
const target = integrations.find((i) => i._id === integrationId);
if (!target) throw new Error('Integration not found');
if (!canManageAll && target._createdBy?._id !== uid) throw new Error('Not your integration');

Type guard

const isDeletableIntegration = (
  i: IIntegration | null | undefined,
  uid: string,
  manageAll: boolean,
): i is IIntegration => !!i && (manageAll || i._createdBy?._id === uid);

Try / catch

try {
  await Meteor.callAsync('deleteOutgoingIntegration', id);
} catch (err) {
  if (err instanceof Meteor.Error && err.error === 'error-invalid-integration') {
    // id is gone or not owned: refresh the list and reconcile local state; do not retry
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: Admin UI holding a stale integration list after concurrent changes; users pasting integration ids they do not own.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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