RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-room
error-invalid-room
Error message
Invalid room
What it means
Thrown by updateIncomingIntegration while resolving each channel target: after stripping the leading '#'/'@', '#x' must match a Room by _id or name and '@x' a User by _id or username. A miss means the referenced room or user does not exist on this server. Note the update payload replaces the whole channel list, so one dead target blocks the entire update.
Source
Thrown at apps/meteor/server/meteor-methods/integrations/incoming/updateIncomingIntegration.ts:130
const channelType = channel[0];
channel = channel.slice(1);
let record;
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', {
method: 'updateIncomingIntegration',
});
}
if (
!(await hasAllPermissionAsync(userId, ['manage-incoming-integrations', 'manage-own-incoming-integrations'])) &&
!(await Subscriptions.findOneByRoomIdAndUserId(record._id, userId, { projection: { _id: 1 } }))
) {
throw new Meteor.Error('error-invalid-channel', 'Invalid Channel', {
method: 'updateIncomingIntegration',
});
}
}
const username = 'username' in integration ? integration.username : currentIntegration.username;
const user = await Users.findOneByUsername(username, { projection: { _id: 1, username: 1 } });
if (!user) {View on GitHub (pinned to b2c16d5842)
Solutions
- Use exact current room names (lowercase slug, no '#') and existing @usernames in every segment
- Remove or recreate dead targets before submitting the update
- Pre-verify each target: GET /api/v1/channels.info?roomName=... or Rooms.findOne({ name }) server-side
Example fix
// before
await Meteor.callAsync('updateIncomingIntegration', id, { ...payload, channel: '#renamed-room,@gone.user' });
// after: only existing targets
await Meteor.callAsync('updateIncomingIntegration', id, { ...payload, channel: '#new-room-name' }); Defensive patterns
Strategy: validation
Validate before calling
// server-side caller: resolve every target before the update
import { Rooms, Users } from '@rocket.chat/models';
for (const entry of channelList.split(',')) {
const type = entry.trim()[0]; const name = entry.trim().slice(1);
const exists = type === '#' ? !!(await Rooms.findOne({ $or: [{ _id: name }, { name }] })) : !!(await Users.findOne({ $or: [{ _id: name }, { username: name }] }));
if (!exists) throw new Error(`target no longer exists: ${entry.trim()}`);
}
await Meteor.callAsync('updateIncomingIntegration', integrationId, { ...integration, channel: channelList }); Try / catch
try {
await Meteor.callAsync('updateIncomingIntegration', integrationId, integration);
} catch (err) {
if (err instanceof Meteor.Error && err.error === 'error-invalid-room') { /* drop dead targets from the list, notify user */ }
} Prevention
- Re-validate stored channel lists whenever rooms are renamed or archived
- Use room pickers over free text
- Add a health-check job that flags integrations referencing missing rooms
When it happens
Trigger: Updating with '#renamed-room' after the room was renamed; '#archived-channel' that was deleted; '@departed.user' whose account was removed; a typo such as '#dev-ops' vs '#devops'.
Common situations: Long-lived integrations whose channel lists go stale as rooms are reorganized; bulk edit tooling applying one channel set to many workspaces where not every room exists; copy-paste between environments.
Related errors
- error-invalid-room
- error-invalid-channel
- error-invalid-channel-start-with-chars
- error-invalid-channel
- error-invalid-channel-start-with-chars
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/ffa784e29a45983f.
Report an issue: GitHub.