RocketChat/Rocket.Chat · error · Error
error-invalid-visitor
error-invalid-visitor
Error message
error-invalid-visitor
What it means
Thrown by POST livechat/room.forward when LivechatVisitors.findOneEnabledById(room.v._id) returns null. The visitor referenced by the room either does not exist or is disabled (archived/deleted via visitor management). Without a live guest record the transfer cannot proceed because guest identity is required for routing and audit.
Source
Thrown at apps/meteor/server/api/v1/omnichannel/room.ts:309
transferredTo?: { _id: string; username?: string; name?: string };
};
const room = await LivechatRooms.findOneById(this.bodyParams.roomId);
if (room?.t !== 'l') {
throw new Error('error-invalid-room');
}
if (!room.open) {
throw new Error('This_conversation_is_already_closed');
}
if (!(await Omnichannel.isWithinMACLimit(room))) {
throw new Error('error-mac-limit-reached');
}
const guest = await LivechatVisitors.findOneEnabledById(room.v?._id);
if (!guest) {
throw new Error('error-invalid-visitor');
}
transferData.transferredBy = normalizeTransferredByData(this.user, room);
if (transferData.userId) {
const userToTransfer = await Users.findOneById(transferData.userId);
if (userToTransfer) {
transferData.transferredTo = {
_id: userToTransfer._id,
username: userToTransfer.username,
name: userToTransfer.name,
};
}
}
const chatForwardedResult = await transfer(room, guest, transferData);
if (!chatForwardedResult) {
throw new Error('error-forwarding-chat');
}View on GitHub (pinned to f9d3ec372b)
Solutions
- Verify the visitor exists and is enabled via GET livechat/visitors.info?token=... or by querying LivechatVisitors directly.
- If the visitor was archived, restore it before retrying the forward.
- Close the orphaned room (livechat/room.close) and start a new conversation rather than transferring a broken one.
- Audit compliance/cleanup jobs that delete visitors to also close their open rooms.
Example fix
// before
await POST('/api/v1/livechat/room.forward', { roomId, userId });
// after
const visitor = await LivechatVisitors.findOneEnabledById(room.v?._id);
if (!visitor) {
await POST('/api/v1/livechat/room.close', { roomId, comment: 'visitor missing' });
return;
}
await POST('/api/v1/livechat/room.forward', { roomId, userId }); Defensive patterns
Strategy: validation
Validate before calling
const visitor = await LivechatVisitors.findOneEnabledById(room.v?._id);
if (!visitor) throw new ClientError('visitor-disabled-or-missing'); Type guard
const hasEnabledVisitor = (room: { v?: { _id?: string } } | null): room is { v: { _id: string } } =>
!!room?.v?._id; Try / catch
try {
await POST('/api/v1/livechat/room.forward', { roomId, userId });
} catch (e) {
if (e.message === 'error-invalid-visitor') { closeOrphanedRoom(roomId); return; }
throw e;
} Prevention
- Ensure compliance/cleanup jobs that delete visitors also close their open rooms.
- Run periodic integrity checks for rooms whose v._id no longer resolves to an enabled visitor.
- Never delete visitors while their rooms are still open.
When it happens
Trigger: POST livechat/room.forward on a room whose v._id points to a visitor that was deleted, archived, or had its enabled flag cleared by a compliance/privacy job. Also occurs if the room document is orphaned (visitor removed manually from the DB).
Common situations: GDPR/cleanup scripts that delete visitors but leave rooms open; LDAP/SSO user purges that cascade to visitors; manual DB surgery that broke the room.visitor link; a migration that recreated visitors with new _ids.
Related errors
- Invalid visitor, cannot create
- Invalid visitor, cannot transfer
- error-room-not-served
- error-invalid-inquiry
- invalid-token
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/43a0f9c777df6a7b.
Report an issue: GitHub.