RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-room
error-invalid-room
Error message
Invalid room
What it means
Thrown by _verifyUserHasPermissionForChannels when a channel entry starts with '#' or '@' but no matching record exists: '#' entries are looked up in Rooms by _id or name, '@' entries in Users by _id or username. A miss means the referenced room or user does not exist (or is not visible), and validation stops with Meteor.Error code 'error-invalid-room'.
Source
Thrown at apps/meteor/server/lib/integrations/lib/validateOutgoingIntegration.ts:83
let record;
const channelType = channel[0];
channel = channel.substr(1);
switch (channelType) {
case '#':
record = await Rooms.findOne({
$or: [{ _id: channel }, { name: channel }],
});
break;
case '@':
record = await Users.findOne({
$or: [{ _id: channel }, { username: channel }],
});
break;
}
if (!record) {
throw new Meteor.Error('error-invalid-room', 'Invalid room', {
function: 'validateOutgoing._verifyUserHasPermissionForChannels',
});
}
if (
!(await hasAllPermissionAsync(userId, ['manage-outgoing-integrations', 'manage-own-outgoing-integrations'])) &&
!(await Subscriptions.findOneByRoomIdAndUserId(record._id, userId, { projection: { _id: 1 } }))
) {
throw new Meteor.Error('error-invalid-channel', 'Invalid Channel', {
function: 'validateOutgoing._verifyUserHasPermissionForChannels',
});
}
}
}
}
function _verifyRetryInformation(integration: IOutgoingIntegration): void {
if (!integration.retryFailedCalls) {View on GitHub (pinned to b2c16d5842)
Solutions
- Correct the channel name/username after the '#'/'@' prefix and re-submit
- Trim each CSV entry before submitting to avoid invisible whitespace mismatches
- Verify existence first: GET /api/v1/channels.info?roomName=... or users.info?username=... for each target
Example fix
// before
{ channel: '#genral' } // typo
// after
{ channel: '#general' } Defensive patterns
Strategy: validation
Validate before calling
const name = channel.slice(1).trim();
const record = channel.startsWith('#')
? await Rooms.findOne({ $or: [{ _id: name }, { name }] })
: await Users.findOne({ $or: [{ _id: name }, { username: name }] });
if (!record) {
throw new Error(`channel ${channel} does not exist`);
} Prevention
- Resolve channels through an autocomplete against channels.list / users.list instead of free-text entry
- Trim CSV entries and re-validate room names right before saving
When it happens
Trigger: integrations.create/update with channel '#genral' (typo), '#general ' (trailing space), '@former.employee' (deleted user), or a room name that was renamed after the integration form was loaded; also '#' followed by a room _id that does not exist.
Common situations: Channel renamed or archived between loading the form and saving; DM target user deleted; copy-pasting display names that differ from the real username (e.g. 'Jane Doe' vs 'jane.doe'); trailing whitespace from CSV splitting.
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
- error-invalid-channel
- error-invalid-channel-start-with-chars
- The integration does not exists.
- error-invalid-integration
- error-invalid-integration-history
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/1a877c0166c8159f.
Report an issue: GitHub.