RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-token

error-invalid-token

Error message

Invalid token

What it means

updateOutgoingIntegration first normalizes the payload through validateOutgoingIntegration, which spreads the caller's fields without generating a token; if the result has no token (or only whitespace), the update is rejected with error-invalid-token before any lookup or permission branch runs. The same path serves both the DDP method and REST PUT /v1/integrations.update, which forwards bodyParams verbatim — so both require a non-empty token in the update payload.

Source

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

declare module '@rocket.chat/ddp-client' {
	// eslint-disable-next-line @typescript-eslint/naming-convention
	interface ServerMethods {
		updateOutgoingIntegration(
			integrationId: string,
			integration: INewOutgoingIntegration | IUpdateOutgoingIntegration,
		): IIntegration | null;
	}
}

export const updateOutgoingIntegration = async (
	userId: string,
	integrationId: string,
	_integration: INewOutgoingIntegration | IUpdateOutgoingIntegration,
): Promise<IIntegration | null> => {
	const integration = await validateOutgoingIntegration(_integration, userId);

	if (!integration.token || integration.token.trim() === '') {
		throw new Meteor.Error('error-invalid-token', 'Invalid token', {
			method: 'updateOutgoingIntegration',
		});
	}

	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',
		});
	}

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Include a non-empty token in the update payload — reuse the integration's existing token or generate a new one to rotate it
  2. Fetch the current token first (GET /v1/integrations.list) if you want to preserve it
  3. Rotate deliberately when needed: sending a fresh token string updates the secret used to authenticate outgoing-webhook handshakes

Example fix

// before
await Meteor.callAsync('updateOutgoingIntegration', integrationId, {
  name: 'new-name',
  channel: '#general', // token omitted -> error-invalid-token
});

// after
await Meteor.callAsync('updateOutgoingIntegration', integrationId, {
  name: 'new-name',
  channel: '#general',
  token: existingIntegration.token, // or a freshly generated value to rotate
});
Defensive patterns

Strategy: validation

Validate before calling

// token is mandatory on every update payload
if (!payload.token || payload.token.trim() === '') {
  payload.token = existingIntegration.token ?? generateToken();
}

Type guard

const hasValidToken = (p: {
  token?: string;
}): p is { token: string } => typeof p.token === 'string' && p.token.trim() !== '';

Try / catch

try {
  await Meteor.callAsync('updateOutgoingIntegration', id, payload);
} catch (err) {
  if (err instanceof Meteor.Error && err.error === 'error-invalid-token') {
    // fill in a non-empty token (existing or rotated) and retry once
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Sending an update payload that omits the token field or sends token: '' — e.g. a partial-update client assuming unspecified fields keep their stored values.

Common situations: Scripts ported from the UI that only send changed fields; API clients modeled on incoming-integration updates where the token is optional.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — 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/c423a78e8fcba902. Report an issue: GitHub.