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

  1. Verify the visitor still exists in the LivechatVisitors collection at the moment the event is processed (race with a concurrent delete/purge).
  2. If you emit IPostLivechatGuestSaved from custom code, ensure the visitor document is committed before dispatching the payload id.
  3. Audit any visitor-deletion path (GDPR purge, omni-core cleanup) that may run between save and event processing and serialize it after event dispatch.
  4. 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

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


AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12). Data as JSON: /api/errors/293920c20463efc7. Report an issue: GitHub.