RocketChat/Rocket.Chat · error · Error

Message converter not found

Error message

Message converter not found

What it means

Thrown by AppRoomBridge.getMessages when the orchestrator's converter registry does not contain a 'messages' converter. Converters are registered during Apps Engine bootstrap; their absence means the orchestrator is not initialized, was torn down, or is in a partially-initialized state. This is an infrastructure/internal-state error, not a user-input error.

Source

Thrown at apps/meteor/app/apps/server/bridges/rooms.ts:152

		this.orch.debugLog(`The App ${appId} is getting the room's creator by name: "${roomName}"`);

		const room = await Rooms.findOneByName(roomName, {});

		if (!room?.u?._id) {
			return undefined;
		}

		return this.orch.getConverters()?.get('users').convertById(room.u._id);
	}

	protected async getMessages(roomId: string, options: GetMessagesOptions, appId: string): Promise<IMessageRaw[]> {
		this.orch.debugLog(`The App ${appId} is getting the messages of the room: "${roomId}" with options:`, options);

		const { limit, skip = 0, sort: _sort, showThreadMessages } = options;

		const messageConverter = this.orch.getConverters()?.get('messages');
		if (!messageConverter) {
			throw new Error('Message converter not found');
		}

		const threadFilterQuery = showThreadMessages ? {} : { tmid: { $exists: false } };

		// We support only one field for now
		const sort: Sort | undefined = _sort?.createdAt ? { ts: _sort.createdAt } : undefined;

		const messageQueryOptions: FindOptions<ICoreMessage> = {
			limit,
			skip,
			sort,
		};

		const query = {
			rid: roomId,
			_hidden: { $ne: true },
			t: { $exists: false },
			...threadFilterQuery,

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Defer getMessages calls until after the Apps Engine is fully initialized (onPostAppInstall or runtime event handlers).
  2. Guard the accessor call: check that the messages accessor is available before invoking getMessages.
  3. In tests, provide a fully-wired orchestrator or mock the converter registry.

Example fix

// before
// called during onPreInstall
const msgs = await rooms.getMessages(roomId, opts);

// after
// called from a command/event handler after install
if (this.orch.getConverters()?.has('messages')) {
  const msgs = await rooms.getMessages(roomId, opts);
}
Defensive patterns

Strategy: validation

Validate before calling

// Only call getMessages after Apps Engine is fully initialized.
// In your handler:
const orch = this.app.getStorage() /* however you reach the orchestrator state */;
// Simplest guard: defer the call to runtime command/event handlers, not lifecycle constructors.

Try / catch

try {
  return await rooms.getMessages(roomId, opts, appId);
} catch (e) {
  if (e instanceof Error && /Message converter not found/.test(e.message)) {
    this.app.getLogger().warn('Messages converter not ready; deferring');
    return [];
  }
  throw e;
}

Prevention

When it happens

Trigger: An App calls the rooms accessor's getMessages during a lifecycle hook that runs before the Apps Engine orchestrator finished wiring its converters, or after the orchestrator was disabled/uninstalled while a queued job still executed. The optional chaining getConverters()?.get('messages') returns undefined and the guard throws.

Common situations: Calling getMessages from onPreInstall / constructor; background jobs that outlive the App's disable; test harness that constructs the bridge without a full orchestrator; version mismatch where the converter key was renamed.

Related errors


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