{"record":{"id":"1241bb56cd31ddc4","repo":"RocketChat/Rocket.Chat","slug":"room-not-found","errorCode":null,"errorMessage":"Room not found","messagePattern":"Room not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/client/apps/RealAppsEngineUIHost.ts","lineNumber":36,"sourceCode":"\t\tsuper();\n\n\t\tthis._baseURL = baseURI.replace(/\\/$/, '');\n\t}\n\n\tprivate getUserAvatarUrl(username: string) {\n\t\tconst avatarUrl = getUserAvatarURL(username)!;\n\n\t\tif (!avatarUrl.startsWith('http') && !avatarUrl.startsWith('data')) {\n\t\t\treturn `${this._baseURL}${avatarUrl}`;\n\t\t}\n\n\t\treturn avatarUrl;\n\t}\n\n\tasync getClientRoomInfo(): Promise<IExternalComponentRoomInfo> {\n\t\tconst room = RoomManager.opened ? Rooms.state.get(RoomManager.opened) : undefined;\n\t\tif (!room) {\n\t\t\tthrow new Error('Room not found');\n\t\t}\n\t\tconst { name: slugifiedName, _id: id } = room;\n\n\t\tlet cachedMembers: IExternalComponentUserInfo[] = [];\n\t\ttry {\n\t\t\tconst { members } = await sdk.rest.get('/v1/groups.members', { roomId: id });\n\n\t\t\tcachedMembers = members.map(\n\t\t\t\t({ _id, username }): IExternalComponentUserInfo => ({\n\t\t\t\t\tid: _id,\n\t\t\t\t\tusername: username!,\n\t\t\t\t\tavatarUrl: this.getUserAvatarUrl(username!),\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconsole.warn(error);\n\t\t}\n","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/client/apps/RealAppsEngineUIHost.ts#L18-L54","documentation":"Thrown by RealAppsEngineUIHost.getClientRoomInfo when there is no currently opened room — either RoomManager.opened is falsy (no room selected) or Rooms.state.get(...) returns undefined for the opened room id (room not in the reactive store). The apps-engine UI host needs a concrete room to populate IExternalComponentRoomInfo, so it fails fast.","triggerScenarios":"An app's UI component calls getClientRoomInfo before any room is opened, after the user navigated away, or when the opened room was evicted from the Rooms store (e.g. cache cleared, room left). RoomManager.opened being null triggers the first condition; a missing store entry triggers the second.","commonSituations":"App view rendered on a screen with no active room; race during room switching where the app initializes before RoomManager.opened is set; the room was just closed/left and the store was pruned; E2E test opening an app route without a room context.","solutions":["Ensure getClientRoomInfo is only called when a room is actually opened — gate the app view on RoomManager.opened.","If the room was left/removed, navigate the user back to a room before re-initializing the app view.","In tests, seed RoomManager.opened and the Rooms store before mounting the app host.","Handle the error to show a 'select a room' state instead of crashing the app view."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const opened = RoomManager.opened;\nif (!opened) { throw new Error('Open a room first'); }\nconst room = Rooms.state.get(opened);\nif (!room) { await loadRoom(opened); }","typeGuard":"function hasOpenedRoom(opened: string | null | undefined): opened is string {\n  return typeof opened === 'string' && opened.length > 0;\n}","tryCatchPattern":"try {\n  const info = await host.getClientRoomInfo();\n} catch (e) {\n  if ((e as Error).message === 'Room not found') {\n    navigateToRoomList();\n  }\n}","preventionTips":["Only mount/initialize app views when RoomManager.opened is set.","Re-fetch room data after switching rooms before calling getClientRoomInfo.","Seed RoomManager.opened and the Rooms store in E2E tests."],"tags":["apps-engine","room","reactive-store","ui-host"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}