RocketChat/Rocket.Chat · error · Error
Invalid visitor, cannot transfer
Error message
Invalid visitor, cannot transfer
What it means
Thrown by AppLivechatBridge.transferVisitor when the visitor argument is falsy. Transfer requires a source visitor to convert and pass to the omni-core transfer function, so an absent visitor aborts before any transfer logic runs. It is a strict precondition on the transfer accessor.
Source
Thrown at apps/meteor/app/apps/server/bridges/livechat.ts:262
id: visitor.id,
...(visitor.phone?.length && { phone: { number: visitor.phone[0].phoneNumber } }),
...(visitor.visitorEmails?.length && { email: visitor.visitorEmails[0].address }),
...(externalIds?.length && { externalIds }),
};
const livechatVisitor = await registerGuest(registerData, {
shouldConsiderIdleAgent: settings.get<boolean>('Livechat_enabled_when_agent_idle'),
shouldConsiderOfflineAgent: settings.get<boolean>('Livechat_accept_chats_with_no_agents'),
});
return this.orch.getConverters()?.get('visitors').convertVisitor(livechatVisitor);
}
protected async transferVisitor(visitor: IVisitor, transferData: ILivechatTransferData, appId: string): Promise<boolean> {
this.orch.debugLog(`The App ${appId} is transfering a livechat.`);
if (!visitor) {
throw new Error('Invalid visitor, cannot transfer');
}
const { targetAgent, targetDepartment: departmentId, currentRoom } = transferData;
const appUser = await Users.findOneByAppId(appId, {});
if (!appUser) {
throw new Error('Invalid app user, cannot transfer');
}
const { _id, username, name, type } = appUser;
const transferredBy = {
_id,
username,
name,
type,
userType: 'user',
} as const;
let userId;View on GitHub (pinned to f9d3ec372b)
Solutions
- Load the visitor via the livechat read accessor before calling transfer and fail fast if it is absent.
- Add a parameter check (if (!visitor) throw ...) in the App so the error message points at the real cause.
- Ensure the call site always has both the room and the visitor in scope.
- Add a type guard so undefined visitors are rejected at compile time.
Example fix
// before
await app.getLivechatModifier().transferVisitor(maybeVisitor, transferData);
// after
if (!visitor) {
throw new Error('Cannot transfer: visitor not loaded for room ' + transferData.currentRoom.id);
}
await app.getLivechatModifier().transferVisitor(visitor, transferData); Defensive patterns
Strategy: validation
Validate before calling
if (!visitor) {
throw new Error('Cannot transfer: visitor was not loaded');
}
await app.getLivechatModifier().transferVisitor(visitor, transferData); Type guard
const isLoadedVisitor = (v: IVisitor | undefined | null): v is IVisitor => Boolean(v && v.token);
Try / catch
try {
return await app.getLivechatModifier().transferVisitor(visitor, transferData);
} catch (e) {
if ((e as Error).message === 'Invalid visitor, cannot transfer') {
// reload visitor from the livechat read accessor and retry once
}
throw e;
} Prevention
- Always load the visitor via the read accessor before transferring.
- Fail fast in the App with a descriptive error if visitor is absent.
- Keep room and visitor in scope together at the call site.
When it happens
Trigger: An App calls the livechat modifier to transfer a room (e.g. app.getLivechatModifier().transferVisitor(visitor, transferData)) with visitor being undefined or null, e.g. the App failed to fetch the visitor before transferring.
Common situations: App transfers by roomId only and forgets to load the visitor; a read accessor returned undefined for the visitor and the App forwarded it unchecked; refactoring changed the call signature and dropped the visitor argument.
Related errors
- Invalid target agent, cannot transfer
- Invalid token for livechat message
- The agent with id "${agent.id}" was not found.
- Invalid agentId
- Invalid visitor, cannot create
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/c9b80c39ba5dd620.
Report an issue: GitHub.