RocketChat/Rocket.Chat · error · Error
Room id not found
Error message
Room id not found
What it means
Thrown by AppRoomBridge.update when Rooms.updateOne({_id: room.id}, {$set: rm}) reports matchedCount === 0. The bridge converts the App's IRoom to a raw room, runs the update, and treats zero matches as 'the room does not exist'. Member additions are skipped because the throw precedes the members loop.
Source
Thrown at apps/meteor/app/apps/server/bridges/rooms.ts:239
protected async getDirectByUsernames(usernames: Array<string>, appId: string): Promise<IRoom | undefined> {
this.orch.debugLog(`The App ${appId} is getting direct room by usernames: "${usernames}"`);
const room = await Rooms.findDirectRoomContainingAllUsernames(usernames, {});
if (!room) {
return undefined;
}
return this.orch.getConverters()?.get('rooms').convertRoom(room);
}
protected async update(room: IRoom, members: Array<string> = [], appId: string): Promise<void> {
this.orch.debugLog(`The App ${appId} is updating a room.`);
const rm = await this.orch.getConverters()?.get('rooms').convertAppRoom(room, true);
const updateResult = await Rooms.updateOne({ _id: room.id }, { $set: rm });
if (!updateResult.matchedCount) {
throw new Error('Room id not found');
}
for (const username of members) {
const member = await Users.findOneByUsername(username, {});
if (!member) {
continue;
}
await addUserToRoom(room.id, member);
}
}
protected async delete(roomId: string, appId: string): Promise<void> {
this.orch.debugLog(`The App ${appId} is deleting a room.`);
await deleteRoom(roomId);
}
View on GitHub (pinned to f9d3ec372b)
Solutions
- Verify the room exists (getById) before calling update, and surface a clear error to the user if not.
- Refresh the IRoom from the accessor before updating so room.id is current.
- If the room may have been deleted, treat matchedCount 0 as a recoverable case in your App's logic rather than propagating the bridge error.
Example fix
// before
await rooms.update(staleRoom, members, appId);
// after
const existing = await rooms.getById(staleRoom.id, appId);
if (!existing) throw new Error(`Room ${staleRoom.id} no longer exists`);
await rooms.update(staleRoom, members, appId); Defensive patterns
Strategy: validation
Validate before calling
const existing = await rooms.getById(room.id, appId);
if (!existing) {
throw new Error(`Cannot update: room ${room.id} does not exist`);
}
await rooms.update(room, members, appId); Try / catch
try {
await rooms.update(room, members, appId);
} catch (e) {
if (e instanceof Error && /Room id not found/.test(e.message)) {
this.app.getLogger().warn({ msg: 'Room disappeared before update', roomId: room.id });
return; // or recreate / re-fetch
}
throw e;
} Prevention
- Refresh the IRoom from the accessor before updating so room.id is current.
- Verify the room exists with getById before attempting an update.
- Treat matchedCount 0 as a recoverable case (room deleted/archived) in your App logic.
When it happens
Trigger: An App calls the rooms accessor's update with a room whose id does not correspond to any persisted room document — a deleted room, a fabricated id, a room on another workspace, or an id extracted from a stale/federated reference that has no local document.
Common situations: Updating a room from a cached IRoom after it was deleted; federation or cross-workspace ids; acting on a webhook for a room that was archived; passing room.id from an object whose id field was never populated.
Related errors
- Only channels, private groups and direct messages can be cre
- Invalid user
- A video conference must exist to update.
- Invalid Api parameter provided, it must be a valid IApi obje
- Invalid command parameter provided, must be a string.
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/cff578c9e08c1c73.
Report an issue: GitHub.