{"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":400,"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/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/api/v1/omnichannel/lib/visitors.ts#L1-L29","documentation":"findVisitorInfo (backing GET /api/v1/livechat/visitors/:visitorId, the visitor-info detail call) uses LivechatVisitors.findOneEnabledById(visitorId). It throws 'visitor-not-found' when no document exists with that _id or the visitor is disabled (findOneEnabledById filters out visitors no longer enabled).","triggerScenarios":"Requesting visitor detail with a mistyped/truncated _id; the visitor record was deleted; the visitor is disabled (e.g. blocked via the omnichannel block/visitor management) so the enabled-only query skips it.","commonSituations":"Ids copied between environments; visitor cleaned up by retention/GDPR tooling after the UI captured the id; blocked visitors still listed in a stale client cache.","solutions":["Re-discover the visitor via the authenticated visitors search/list endpoint and copy the exact _id.","If the visitor was blocked or disabled intentionally, treat this as a 404 and stop showing detail.","Confirm you are querying the same server/environment that produced the id."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const OBJ_ID = /^[0-9a-f]{24}$/i;\nfunction isVisitorId(v: string): boolean { return OBJ_ID.test(v); }\nif (!isVisitorId(visitorId)) throw new TypeError('malformed visitorId');\nconst { visitors } = await get(`/api/v1/livechat/visitors?term=${encodeURIComponent(nameOrEmail)}`);\nconst exact = visitors.find((v) => v._id === visitorId);\nif (!exact) throw new NotFoundError('visitor missing or disabled');\nconst { visitor } = await getVisitorInfo(visitorId);","typeGuard":null,"tryCatchPattern":"try { visitor = await getVisitorInfo(visitorId); } catch (e) { if (e.message === 'visitor-not-found') return renderNotFound(); throw e; }","preventionTips":["Treat visitor-not-found as expected for blocked/disabled visitors; render empty state.","Refresh ids from search rather than caching them long-term.","Remember the lookup is enabled-only: disabled visitors behave like deleted ones."],"tags":["omnichannel","visitors","livechat","rest-api"],"backgroundTag":"resource-not-found","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}