{"record":{"id":"402e0bb9d126ad20","repo":"RocketChat/Rocket.Chat","slug":"message-converter-not-found","errorCode":null,"errorMessage":"Message converter not found","messagePattern":"Message converter not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/app/apps/server/bridges/rooms.ts","lineNumber":152,"sourceCode":"\t\tthis.orch.debugLog(`The App ${appId} is getting the room's creator by name: \"${roomName}\"`);\n\n\t\tconst room = await Rooms.findOneByName(roomName, {});\n\n\t\tif (!room?.u?._id) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn this.orch.getConverters()?.get('users').convertById(room.u._id);\n\t}\n\n\tprotected async getMessages(roomId: string, options: GetMessagesOptions, appId: string): Promise<IMessageRaw[]> {\n\t\tthis.orch.debugLog(`The App ${appId} is getting the messages of the room: \"${roomId}\" with options:`, options);\n\n\t\tconst { limit, skip = 0, sort: _sort, showThreadMessages } = options;\n\n\t\tconst messageConverter = this.orch.getConverters()?.get('messages');\n\t\tif (!messageConverter) {\n\t\t\tthrow new Error('Message converter not found');\n\t\t}\n\n\t\tconst threadFilterQuery = showThreadMessages ? {} : { tmid: { $exists: false } };\n\n\t\t// We support only one field for now\n\t\tconst sort: Sort | undefined = _sort?.createdAt ? { ts: _sort.createdAt } : undefined;\n\n\t\tconst messageQueryOptions: FindOptions<ICoreMessage> = {\n\t\t\tlimit,\n\t\t\tskip,\n\t\t\tsort,\n\t\t};\n\n\t\tconst query = {\n\t\t\trid: roomId,\n\t\t\t_hidden: { $ne: true },\n\t\t\tt: { $exists: false },\n\t\t\t...threadFilterQuery,","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/app/apps/server/bridges/rooms.ts#L134-L170","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Defer getMessages calls until after the Apps Engine is fully initialized (onPostAppInstall or runtime event handlers).","Guard the accessor call: check that the messages accessor is available before invoking getMessages.","In tests, provide a fully-wired orchestrator or mock the converter registry."],"exampleFix":"// before\n// called during onPreInstall\nconst msgs = await rooms.getMessages(roomId, opts);\n\n// after\n// called from a command/event handler after install\nif (this.orch.getConverters()?.has('messages')) {\n  const msgs = await rooms.getMessages(roomId, opts);\n}","handlingStrategy":"validation","validationCode":"// Only call getMessages after Apps Engine is fully initialized.\n// In your handler:\nconst orch = this.app.getStorage() /* however you reach the orchestrator state */;\n// Simplest guard: defer the call to runtime command/event handlers, not lifecycle constructors.","typeGuard":null,"tryCatchPattern":"try {\n  return await rooms.getMessages(roomId, opts, appId);\n} catch (e) {\n  if (e instanceof Error && /Message converter not found/.test(e.message)) {\n    this.app.getLogger().warn('Messages converter not ready; deferring');\n    return [];\n  }\n  throw e;\n}","preventionTips":["Do not call accessor methods from onPreInstall or the App constructor.","Prefer runtime command/event handlers that run after Apps Engine bootstrap completes.","In tests, wire a full orchestrator or mock the accessor rather than the bridge."],"tags":["apps-engine","room-bridge","orchestrator","converter","initialization","internal-state"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}