{"record":{"id":"d926e682a900e1a4","repo":"RocketChat/Rocket.Chat","slug":"visitor-not-found","errorCode":null,"errorMessage":"visitor-not-found","messagePattern":"visitor-not-found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/api/v1/omnichannel/lib/visitors.ts","lineNumber":11,"sourceCode":"import type { ILivechatVisitor, IMessage, IOmnichannelRoom, IRoom, IUser, IVisitor } from '@rocket.chat/core-typings';\nimport { LivechatVisitors, Messages, LivechatRooms, LivechatCustomField } from '@rocket.chat/models';\nimport type { FindOptions } from 'mongodb';\n\nimport { canAccessRoomAsync } from '../../../../lib/authorization/canAccessRoom';\nimport { callbacks } from '../../../../lib/callbacks';\n\nexport async function findVisitorInfo({ visitorId }: { visitorId: IVisitor['_id'] }) {\n\tconst visitor = await LivechatVisitors.findOneEnabledById(visitorId, { projection: { token: 0 } });\n\tif (!visitor) {\n\t\tthrow new Error('visitor-not-found');\n\t}\n\n\treturn {\n\t\tvisitor,\n\t};\n}\n\nexport async function findVisitedPages({\n\troomId,\n\tpagination: { offset, count, sort },\n}: {\n\troomId: IRoom['_id'];\n\tpagination: { offset: number; count: number; sort: FindOptions<IMessage>['sort'] };\n}) {\n\tconst room = await LivechatRooms.findOneById(roomId);\n\tif (!room) {\n\t\tthrow new Error('invalid-room');\n\t}","sourceCodeStart":1,"sourceCodeEnd":29,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/omnichannel/lib/visitors.ts#L1-L29","documentation":"Thrown by findVisitorInfo (visitors.ts:8-12) when LivechatVisitors.findOneEnabledById(visitorId) returns null. This means either no visitor exists with that `_id`, or the visitor record exists but is disabled (the query uses the *Enabled* variant). The token field is projected out of the result. Returns HTTP 400 { success:false, error:'visitor-not-found' }.","triggerScenarios":"Calling findVisitorInfo / the visitor-info endpoint with a visitorId that does not exist or has been disabled.","commonSituations":"Passing the visitor `token` where the visitor `_id` is expected; visitor disabled via contact-merge or GDPR/right-to-erasure deletion; stale id persisted client-side.","solutions":["Confirm the visitor exists and is enabled via LivechatVisitors.findOneEnabledById before calling.","Do not confuse visitor `token` with visitor `_id`; this function takes `_id`.","If the visitor was disabled/deleted, restore or recreate it."],"exampleFix":"// before\nconst { visitor } = await findVisitorInfo({ visitorId: maybeAToken }); // throws visitor-not-found\n\n// after\nconst visitor = await LivechatVisitors.findOneEnabledById(visitorId);\nif (!visitor) return notFound();\nconst info = await findVisitorInfo({ visitorId: visitor._id });","handlingStrategy":"validation","validationCode":"const visitor = await LivechatVisitors.findOneEnabledById(visitorId);\nif (!visitor) {\n  throw new Error('visitor does not exist or is disabled');\n}\n// safe to call findVisitorInfo({ visitorId })","typeGuard":"const visitorExists = async (id: string) => !!(await LivechatVisitors.findOneEnabledById(id, { projection: { _id: 1 } }));","tryCatchPattern":"try {\n  await findVisitorInfo({ visitorId });\n} catch (e) {\n  if (e instanceof Error && e.message === 'visitor-not-found') {\n    // 404 to client or recreate the visitor\n  } else { throw e; }\n}","preventionTips":["Pass the visitor `_id`, never the `token`, to findVisitorInfo.","Treat disabled visitors as not-found; restore or recreate instead of retrying.","Validate the id shape/source before calling."],"tags":["livechat","omnichannel","visitor","rest-api"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}