RocketChat/Rocket.Chat · warning · Error
Visitor with id ${visitorId} not found
Error message
Visitor with id ${visitorId} not found What it means
Thrown by the livechatEvent handler in the apps-engine bridge when an IPostLivechatGuestSaved event fires with a visitorId, but the visitors converter's convertById returns null/undefined. The bridge refuses to dispatch the event to registered App listeners because the payload object cannot be materialized. It indicates the visitor record is gone or never existed by the time the after-save hook runs.
Source
Thrown at apps/meteor/app/apps/server/bridges/listeners.ts:466
}
return this.orch
.getManager()
.getListenerManager()
.executeListener(args.event, {
room,
from: from as NonNullable<typeof from>, // type definition in the apps-engine seems to be incorrect
to,
type: transferData.type,
});
}
case AppInterface.IPostLivechatGuestSaved: {
const [visitorId] = args.payload;
const visitor = await this.orch.getConverters().get('visitors').convertById(visitorId);
if (!visitor) {
throw new Error(`Visitor with id ${visitorId} not found`);
}
return this.orch.getManager().getListenerManager().executeListener(args.event, visitor);
}
case AppInterface.IPostLivechatRoomSaved: {
const [roomId] = args.payload;
const room = await this.orch.getConverters().get('rooms').convertById(roomId);
if (!room) {
throw new Error(`Room with id ${roomId} not found`);
}
return this.orch
.getManager()
.getListenerManager()
.executeListener(args.event, room as IAppsLivechatRoom);
}View on GitHub (pinned to f9d3ec372b)
Solutions
- Verify the visitor still exists in the LivechatVisitors collection at the moment the event is processed (race with a concurrent delete/purge).
- If you emit IPostLivechatGuestSaved from custom code, ensure the visitor document is committed before dispatching the payload id.
- Audit any visitor-deletion path (GDPR purge, omni-core cleanup) that may run between save and event processing and serialize it after event dispatch.
- Check Mongo/oplog replication health if this appears intermittently in a clustered deployment.
Example fix
// before: visitor deleted before after-save hook converts it
await LivechatVisitors.removeById(visitorId);
await emitEvent(IPostLivechatGuestSaved, { payload: [visitorId] }); // convertById now fails
// after: dispatch event first, then remove (or skip dispatch for removed records)
await emitEvent(IPostLivechatGuestSaved, { payload: [visitorId] });
await LivechatVisitors.removeById(visitorId); Defensive patterns
Strategy: try-catch
Validate before calling
// The throw happens inside the bridge before the App listener runs,
// so the App cannot pre-validate. Ensure the visitor exists when the
// event is emitted:
const visitor = await LivechatVisitors.findOneById(visitorId);
if (!visitor) {
// skip emitting IPostLivechatGuestSaved for a non-existent visitor
return;
}
await emitEvent(AppInterface.IPostLivechatGuestSaved, { payload: [visitorId] }); Type guard
const isPersistedVisitorId = async (id: string): Promise<boolean> => {
return Boolean(await LivechatVisitors.findOneById(id, { projection: { _id: 1 } }));
}; Try / catch
// Framework-level: the apps-engine swallows and logs this throw.
// In a custom bridge wrapper, catch and degrade gracefully:
try {
await listenerManager.executeListener(args.event, visitor);
} catch (e) {
this.orch.debugLog(`Skipping ${args.event}: ${(e as Error).message}`);
} Prevention
- Do not delete visitors in a path that also emits IPostLivechatGuestSaved.
- Serialize purges/GDPR deletions to run after livechat events drain.
- When emitting the event from custom code, confirm the visitor document is committed first.
When it happens
Trigger: Server emits IPostLivechatGuestSaved with a visitorId; this.orch.getConverters().get('visitors').convertById(visitorId) resolves to a falsy value (the LivechatVisitors document was deleted, not yet replicated, or the id is stale between event enqueue and processing).
Common situations: A migration or purge job deletes visitors concurrently with guest-save events; a custom integration fires IPostLivechatGuestSaved manually with a wrong id; replication lag in a sharded Mongo setup; an App's own before-hook removed the visitor before the after-hook converted it.
Related errors
- Room with id ${roomId} not found
- Department ${departmentData._id} not found
- Room ${roomData._id} not found
- Room ${roomData._id} is not a livechat room
- Room with id ${transferData.room} not found
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/293920c20463efc7.
Report an issue: GitHub.