{"record":{"id":"c9b80c39ba5dd620","repo":"RocketChat/Rocket.Chat","slug":"invalid-visitor-cannot-transfer","errorCode":null,"errorMessage":"Invalid visitor, cannot transfer","messagePattern":"Invalid visitor, cannot transfer","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/app/apps/server/bridges/livechat.ts","lineNumber":262,"sourceCode":"\t\t\tid: visitor.id,\n\t\t\t...(visitor.phone?.length && { phone: { number: visitor.phone[0].phoneNumber } }),\n\t\t\t...(visitor.visitorEmails?.length && { email: visitor.visitorEmails[0].address }),\n\t\t\t...(externalIds?.length && { externalIds }),\n\t\t};\n\n\t\tconst livechatVisitor = await registerGuest(registerData, {\n\t\t\tshouldConsiderIdleAgent: settings.get<boolean>('Livechat_enabled_when_agent_idle'),\n\t\t\tshouldConsiderOfflineAgent: settings.get<boolean>('Livechat_accept_chats_with_no_agents'),\n\t\t});\n\n\t\treturn this.orch.getConverters()?.get('visitors').convertVisitor(livechatVisitor);\n\t}\n\n\tprotected async transferVisitor(visitor: IVisitor, transferData: ILivechatTransferData, appId: string): Promise<boolean> {\n\t\tthis.orch.debugLog(`The App ${appId} is transfering a livechat.`);\n\n\t\tif (!visitor) {\n\t\t\tthrow new Error('Invalid visitor, cannot transfer');\n\t\t}\n\n\t\tconst { targetAgent, targetDepartment: departmentId, currentRoom } = transferData;\n\n\t\tconst appUser = await Users.findOneByAppId(appId, {});\n\t\tif (!appUser) {\n\t\t\tthrow new Error('Invalid app user, cannot transfer');\n\t\t}\n\t\tconst { _id, username, name, type } = appUser;\n\t\tconst transferredBy = {\n\t\t\t_id,\n\t\t\tusername,\n\t\t\tname,\n\t\t\ttype,\n\t\t\tuserType: 'user',\n\t\t} as const;\n\n\t\tlet userId;","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/app/apps/server/bridges/livechat.ts#L244-L280","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait app.getLivechatModifier().transferVisitor(maybeVisitor, transferData);\n\n// after\nif (!visitor) {\n  throw new Error('Cannot transfer: visitor not loaded for room ' + transferData.currentRoom.id);\n}\nawait app.getLivechatModifier().transferVisitor(visitor, transferData);","handlingStrategy":"validation","validationCode":"if (!visitor) {\n  throw new Error('Cannot transfer: visitor was not loaded');\n}\nawait app.getLivechatModifier().transferVisitor(visitor, transferData);","typeGuard":"const isLoadedVisitor = (v: IVisitor | undefined | null): v is IVisitor =>\n  Boolean(v && v.token);","tryCatchPattern":"try {\n  return await app.getLivechatModifier().transferVisitor(visitor, transferData);\n} catch (e) {\n  if ((e as Error).message === 'Invalid visitor, cannot transfer') {\n    // reload visitor from the livechat read accessor and retry once\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["apps-engine","livechat","transfer","visitor","validation"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}