RocketChat/Rocket.Chat · error · Error
error-unserved-rooms-cannot-be-placed-onhold
Error message
error-unserved-rooms-cannot-be-placed-onhold
What it means
placeRoomOnHold requires an assigned agent: if room.servedBy is unset it throws Error('error-unserved-rooms-cannot-be-placed-onhold'). On-hold semantics depend on the serving agent (resume returns the chat to them), so chats still in queue or whose servedBy was cleared cannot be held.
Solutions
- Assign an agent (take the chat) before placing it on hold.
- Exclude rooms without servedBy from bulk on-hold operations.
- If servedBy was unexpectedly cleared, fix department/agent routing before retrying the hold.
Example fix
// before
for (const r of openRooms) await service.placeRoomOnHold(r, comment, user); // queued rooms throw
// after
for (const r of openRooms) {
if (!r.servedBy) continue; // unserved/queued chats cannot be held
await service.placeRoomOnHold(r, comment, user);
} Defensive patterns
Strategy: validation
Validate before calling
if (!room.servedBy) {
// no assigned agent (still queued or assignment cleared); on-hold is not applicable
} Try / catch
try {
await service.placeRoomOnHold(room, comment, user);
} catch (e: any) {
if (e?.message === 'error-unserved-rooms-cannot-be-placed-onhold') { surface('Assign an agent before placing the chat on hold'); return; }
throw e;
} Prevention
- Filter servedBy from room lists used by bulk hold operations.
- Ensure chats are taken by an agent before exposing hold actions.
- Investigate cleared servedBy values (routing changes) rather than retrying the hold.
When it happens
Trigger: Attempting to hold a chat that was never taken by an agent (still queued) or whose servedBy was cleared - e.g. the agent was removed, the chat was returned to the queue, or department re-routing reset assignment.
Common situations: Bulk on-hold automation sweeping all open rooms including untouched queue items; stale room data missing servedBy; chats returned to queue between the UI read and the hold call.
Related errors
- error-room-already-closed
- error-room-is-already-on-hold
- error-cannot-place-chat-on-hold
- error-invalid-room
- error-room-onHold
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/c5d83dfa77dc76ac.
Report an issue: GitHub.
Appendix: source
Thrown at apps/meteor/ee/server/local-services/omnichannel.internalService.ts:57
if (!room || !isOmnichannelRoom(room)) {
throw new Error('error-invalid-room');
}
if (!room.open) {
throw new Error('error-room-already-closed');
}
if (room.onHold) {
throw new Error('error-room-is-already-on-hold');
}
const restrictedOnHold = settings.get('Livechat_allow_manual_on_hold_upon_agent_engagement_only');
const canRoomBePlacedOnHold = !room.onHold;
const canAgentPlaceOnHold = !room.lastMessage?.token;
const canPlaceChatOnHold = canRoomBePlacedOnHold && (!restrictedOnHold || canAgentPlaceOnHold);
if (!canPlaceChatOnHold) {
throw new Error('error-cannot-place-chat-on-hold');
}
if (!room.servedBy) {
throw new Error('error-unserved-rooms-cannot-be-placed-onhold');
}
const [roomResult, subsResult] = await Promise.all([
LivechatRooms.setOnHoldByRoomId(roomId),
Subscriptions.setOnHoldByRoomId(roomId),
Message.saveSystemMessage<IOmnichannelSystemMessage>('omnichannel_placed_chat_on_hold', roomId, '', onHoldBy, { comment }),
]);
if (roomResult.modifiedCount) {
void notifyOnRoomChangedById(roomId);
}
if (subsResult.modifiedCount) {
void notifyOnSubscriptionChangedByRoomId(roomId);
}
await callbacks.run('livechat:afterOnHold', room);
}View on GitHub (pinned to b2c16d5842)