RocketChat/Rocket.Chat · error · Meteor.Error

invalid_integration

invalid_integration

Error message

[methods] updateOutgoingIntegration -> integration not found

What it means

Thrown when the permission branch succeeded but the integration lookup returned null: either the id does not exist at all, or the caller holds only manage-own-outgoing-integrations and the query's _createdBy._id === userId filter excluded an integration owned by someone else. The code is invalid_integration (with underscores), distinct from error-invalid-integration used by the delete path.

Source

Thrown at apps/meteor/server/meteor-methods/integrations/outgoing/updateOutgoingIntegration.ts:52

	}

	let currentIntegration: IIntegration | null;

	if (await hasPermissionAsync(userId, 'manage-outgoing-integrations')) {
		currentIntegration = await Integrations.findOneById(integrationId);
	} else if (await hasPermissionAsync(userId, 'manage-own-outgoing-integrations')) {
		currentIntegration = await Integrations.findOne({
			'_id': integrationId,
			'_createdBy._id': userId,
		});
	} else {
		throw new Meteor.Error('not_authorized', 'Unauthorized', {
			method: 'updateOutgoingIntegration',
		});
	}

	if (!currentIntegration) {
		throw new Meteor.Error('invalid_integration', '[methods] updateOutgoingIntegration -> integration not found');
	}

	const oldScriptEngine = currentIntegration.scriptEngine;
	const scriptEngine = integration.scriptEngine ?? oldScriptEngine ?? 'isolated-vm';
	if (
		integration.script?.trim() &&
		(scriptEngine !== oldScriptEngine || integration.script?.trim() !== currentIntegration.script?.trim())
	) {
		wrapExceptions(() => validateScriptEngine(scriptEngine)).catch((e) => {
			throw new Meteor.Error(e.message);
		});
	}

	const isFrozen = isScriptEngineFrozen(scriptEngine);

	const updatedIntegration = await Integrations.findOneAndUpdate(
		{ _id: integrationId },
		{

View on GitHub (pinned to b2c16d5842)

Solutions

  1. List integrations (GET /v1/integrations.list?type=webhook-outgoing) and confirm the exact _id still exists
  2. If you hold only manage-own permissions, verify _createdBy._id matches your userId or hand the task to an admin
  3. Refresh the UI data before retrying so you edit a live record

Example fix

// before
await Meteor.callAsync('updateOutgoingIntegration', staleId, payload);

// after
const res = await fetch('/api/v1/integrations.list?type=webhook-outgoing', { headers });
const { integrations } = await res.json();
const current = integrations.find((i) => i._id === staleId);
if (!current) throw new Error('Integration no longer exists');
await Meteor.callAsync('updateOutgoingIntegration', current._id, payload);
Defensive patterns

Strategy: validation

Validate before calling

// confirm existence and ownership before updating
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 isUpdatableIntegration = (
  i: IIntegration | null | undefined,
  uid: string,
  manageAll: boolean,
): i is IIntegration => !!i && (manageAll || i._createdBy?._id === uid);

Try / catch

try {
  await Meteor.callAsync('updateOutgoingIntegration', id, payload);
} catch (err) {
  if (err instanceof Meteor.Error && err.error === 'invalid_integration') {
    // record gone or not owned: refresh the list, do not retry the stale id
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Updating a deleted or mistyped integrationId; owning-only permissions while updating another user's integration; stale UI list referencing a removed integration.

Common situations: Concurrent admins editing/removing the same webhook; copied ids with whitespace or truncation; permission model misunderstanding where manage-own silently hides other users' integrations.

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/9ab1ab4ea519b109. Report an issue: GitHub.