RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-channel

error-invalid-channel

Error message

Invalid channel

What it means

Thrown by the deprecated addIncomingIntegration Meteor method when integration.channel is falsy or not a string. The channel field is a single comma-separated string listing the rooms ('#name') and users ('@username') the incoming webhook may post to. Note the method first runs Meteor's check() requiring channel: String, so missing or non-string values usually surface earlier as a 'Match failed' Match.Error; this explicit error most commonly fires for channel: '' (empty string is falsy).

Source

Thrown at apps/meteor/server/meteor-methods/integrations/incoming/addIncomingIntegration.ts:54

			scriptEngine: Match.Maybe(String),
			overrideDestinationChannelEnabled: Match.Maybe(Boolean),
			script: Match.Maybe(String),
			avatar: Match.Maybe(String),
		}),
	);

	if (
		!userId ||
		(!(await hasPermissionAsync(userId, 'manage-incoming-integrations')) &&
			!(await hasPermissionAsync(userId, 'manage-own-incoming-integrations')))
	) {
		throw new Meteor.Error('not_authorized', 'Unauthorized', {
			method: 'addIncomingIntegration',
		});
	}

	if (!integration.channel || typeof integration.channel.valueOf() !== 'string') {
		throw new Meteor.Error('error-invalid-channel', 'Invalid channel', {
			method: 'addIncomingIntegration',
		});
	}

	if (integration.channel.trim() === '') {
		throw new Meteor.Error('error-invalid-channel', 'Invalid channel', {
			method: 'addIncomingIntegration',
		});
	}

	const channels = integration.channel.split(',').map((channel) => channel.trim());

	for (const channel of channels) {
		if (!validChannelChars.includes(channel[0])) {
			throw new Meteor.Error('error-invalid-channel-start-with-chars', 'Invalid channel. Start with @ or #', {
				method: 'updateIncomingIntegration',
			});
		}

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Set channel to a non-empty comma-separated string where every entry starts with # (room) or @ (user), e.g. '#general,@rocket.cat'
  2. If you instead see 'Match failed', the channel is missing or not a string at all - send it as a primitive string, never an array or object
  3. Prefer the REST endpoint POST /api/v1/integrations.create; these Meteor methods are deprecated and removed in 9.0.0

Example fix

// before
Meteor.callAsync('addIncomingIntegration', { ...integration, channel: '' });
// after
Meteor.callAsync('addIncomingIntegration', { ...integration, channel: '#general,@rocket.cat' });
Defensive patterns

Strategy: validation

Validate before calling

const channelOk = (channel) => typeof channel === 'string' && channel.length > 0;
if (!channelOk(integration.channel)) throw new Error('channel must be a non-empty "#room,@user" string');
await Meteor.callAsync('addIncomingIntegration', integration);

Type guard

const isNonEmptyChannelString = (c: unknown): c is string => typeof c === 'string' && c.length > 0;

Try / catch

try {
  await Meteor.callAsync('addIncomingIntegration', integration);
} catch (err) {
  if (err instanceof Meteor.Error && err.error === 'error-invalid-channel') { /* prompt user for channel */ return; }
  throw err;
}

Prevention

When it happens

Trigger: Meteor.callAsync('addIncomingIntegration', integration) with channel: '' or channel: null (the latter only when calling the exported helper directly, e.g. in tests, since check() intercepts it on the method path).

Common situations: A custom integration form was submitted with the channel field left blank; payload built from array.join() on an empty array; migrating from the REST endpoint /api/v1/integrations.create and forgetting the DDP method wants one comma-separated string; calling this DDP method on a 9.0.0+ server where it has been removed.

Related errors


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