RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-channel-start-with-chars
error-invalid-channel-start-with-chars
Error message
Invalid channel. Start with @ or #
What it means
Thrown by updateIncomingIntegration's validateChannels when a comma-separated channel entry does not start with '#' or '@'. The string is split on ',', trimmed, and each segment's first character is checked against ['@', '#']. Empty segments from trailing or double commas also trigger it because channel[0] is undefined.
Source
Thrown at apps/meteor/server/meteor-methods/integrations/incoming/updateIncomingIntegration.ts:36
updateIncomingIntegration(
integrationId: string,
integration: INewIncomingIntegration | IUpdateIncomingIntegration,
): IIntegration | null;
}
}
function validateChannels(channelString: string | undefined): string[] {
if (!channelString || typeof channelString.valueOf() !== 'string' || channelString.trim() === '') {
throw new Meteor.Error('error-invalid-channel', 'Invalid channel', {
method: 'updateIncomingIntegration',
});
}
const channels = channelString.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',
});
}
}
return channels;
}
export const updateIncomingIntegration = async (
userId: string,
integrationId: string,
integration: INewIncomingIntegration | IUpdateIncomingIntegration,
): Promise<IIntegration | null> => {
const channels = validateChannels(integration.channel);
let currentIntegration;
if (await hasPermissionAsync(userId, 'manage-incoming-integrations')) {View on GitHub (pinned to b2c16d5842)
Solutions
- Prefix rooms with # and users with @ in every segment: '#general,#dev,@rocket.cat'
- Normalize before submitting: split, trim, filter(Boolean), re-add prefixes, join
- Validate in the form layer so the update call never carries malformed segments
Example fix
// before
await Meteor.callAsync('updateIncomingIntegration', id, { ...payload, channel: 'general, dev' });
// after
const channel = payload.channel.split(',').map((c) => c.trim()).filter(Boolean).map((c) => (/^[#@]/.test(c) ? c : `#${c}`)).join(',');
await Meteor.callAsync('updateIncomingIntegration', id, { ...payload, channel }); Defensive patterns
Strategy: validation
Validate before calling
const segments = integration.channel.split(',').map((s) => s.trim()).filter(Boolean);
if (segments.some((s) => !['@', '#'].includes(s[0]))) throw new Error('each channel entry must start with # or @');
await Meteor.callAsync('updateIncomingIntegration', integrationId, { ...integration, channel: segments.join(',') }); Type guard
const isValidChannelList = (c: unknown): c is string =>
typeof c === 'string' && c.trim() !== '' &&
c.split(',').every((s) => ['@', '#'].includes(s.trim()[0])); Try / catch
try {
await Meteor.callAsync('updateIncomingIntegration', integrationId, integration);
} catch (err) {
if (err instanceof Meteor.Error && err.error === 'error-invalid-channel-start-with-chars') { /* normalize segments and resubmit */ }
} Prevention
- Share one channel-string builder between create and update paths
- Filter empty segments from multi-select joins
- Lint form payloads before submission
When it happens
Trigger: channel: 'general' on update; 'general,#dev'; trailing comma '#general,'; double comma '#general,,#ops'.
Common situations: Edit forms that join a channel multi-select with ',' but include an empty option; hand-edited channel lists; porting from the old outgoing-integration payload style without prefixes.
Related errors
- error-invalid-channel-start-with-chars
- error-invalid-channel
- error-invalid-room
- error-invalid-channel
- error-invalid-room
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/067992f01a7d771e.
Report an issue: GitHub.