RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-user
error-invalid-user
Error message
error-invalid-user
What it means
After the state and MAC checks, returnRoomAsInquiry loads the serving agent with Users.findOneById(room.servedBy._id). If that user no longer exists in the users collection, it throws Meteor.Error('error-invalid-user') — the room references an agent that was deleted.
Source
Thrown at apps/meteor/server/lib/omnichannel/rooms.ts:240
if (!room.open) {
throw new Meteor.Error('room-closed', 'Room closed');
}
if (room.onHold) {
throw new Meteor.Error('error-room-onHold');
}
if (!(await Omnichannel.isWithinMACLimit(room))) {
throw new Meteor.Error('error-mac-limit-reached');
}
if (!room.servedBy) {
return false;
}
const user = await Users.findOneById(room.servedBy._id);
if (!user?._id) {
throw new Meteor.Error('error-invalid-user');
}
const inquiry = await LivechatInquiry.findOne({ rid: room._id });
if (!inquiry) {
return false;
}
// update inquiry's last message with room's last message to correctly display in the queue
// because we stop updating the inquiry when it's been taken
if (room.lastMessage) {
await LivechatInquiry.setLastMessageById(inquiry._id, room.lastMessage);
}
const transferredBy = normalizeTransferredByData(user, room);
livechatLogger.debug({ msg: 'Transferring room by user', roomId: room._id, transferredBy: transferredBy._id });
const transferData = { scope: 'queue' as const, departmentId, transferredBy, ...overrideTransferData };
try {
await saveTransferHistory(room, transferData);View on GitHub (pinned to b2c16d5842)
Solutions
- Restore or re-create the agent user, or clear/reassign room.servedBy before returning the room.
- Audit for orphan rooms (servedBy._id missing from users) after any bulk user deletion.
- Only delete users after their open omnichannel rooms are closed or transferred.
Example fix
// before
await returnRoomAsInquiry(room, departmentId); // servedBy agent deleted -> error-invalid-user
// after
const agent = room.servedBy ? await Users.findOneById(room.servedBy._id, { projection: { _id: 1 } }) : null;
if (!agent) {
// reassign or clear the stale agent reference first
await LivechatRooms.unsetAgentByRoomId(room._id);
}
await returnRoomAsInquiry(room, departmentId); Defensive patterns
Strategy: validation
Validate before calling
const agent = room.servedBy
? await Users.findOneById(room.servedBy._id, { projection: { _id: 1 } })
: null;
if (!agent) {
// reassign or clear the stale servedBy reference before returning the room
} Type guard
const hasLiveServingAgent = async (room: Pick<IOmnichannelRoom, 'servedBy'>): Promise<boolean> =>
Boolean(room.servedBy && (await Users.findOneById(room.servedBy._id, { projection: { _id: 1 } }))); Try / catch
try {
await returnRoomAsInquiry(room, departmentId);
} catch (err) {
if (err instanceof Meteor.Error && err.error === 'error-invalid-user') {
// serving agent is gone: repair room.servedBy or close the orphan room
return;
}
throw err;
} Prevention
- Close or transfer open omnichannel rooms before deleting agent users.
- Run periodic audits for rooms whose servedBy._id no longer resolves.
- After DB restores/imports, validate referential integrity between rooms and users.
When it happens
Trigger: Returning a room to the queue when the agent recorded in room.servedBy has been deleted from the database, leaving the reference dangling.
Common situations: Agent user hard-deleted while still serving chats; imported/restored database with orphan rooms; user-deletion cascades that skip livechat room cleanup.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/466472756de0741a.
Report an issue: GitHub.