RocketChat/Rocket.Chat · error · Error

Room with id not found

Error message

Room with id ${transferData.room} not found

What it means

UserDataFiles (GDPR export downloads) resolves the requester via FileUpload.getRequestUserId — rc_uid/rc_token from the query or cookies, or x-user-id/x-auth-token headers — and only permits the export's owner (uid === file.userId). Missing credentials, an invalid/expired token, or any other user yields a bodyless 403. This is stricter than room-based upload protection: exports are owner-only, always.

Solutions

  1. Download the export while logged in as the user who requested it, using the link from their notification/email
  2. Pass x-user-id and x-auth-token headers (or rc_uid/rc_token query params) of the owner on programmatic requests
  3. If the token expired, log in again and reopen the export link
  4. Do not try to bypass with admin privileges — the check is owner identity, not permission

Example fix

// before
await fetch(`${site}/file-upload/${fileId}/${name}`);
// after: authenticate as the owner
await fetch(`${site}/file-upload/${fileId}/${name}`, { headers: { 'x-user-id': uid, 'x-auth-token': token } });
Defensive patterns

Strategy: validation

Validate before calling

const uid = await FileUpload.getRequestUserId(req);
if (!uid || uid !== file.userId) { /* do not fetch; have the owner's session make the request */ }

Type guard

const isOwnerRequest = (requesterId?: string, ownerId: string): boolean => requesterId === ownerId;

Try / catch

On 403 from a user-data export link, redirect to login and retry once as the owner; a second 403 means the authenticated user is not the owner — surface that explicitly.

Prevention

When it happens

Trigger: Downloading another user's export link while authenticated as someone else (including admins); anonymous fetch of an export URL; rc_token expired between the export email and the click; automated fetchers that strip cookies/headers.

Common situations: Forwarded export links; curl/wget downloads without credentials; admins attempting to fetch users' exports directly instead of through the proper flow; sessions expiring before download.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/1ef9e61fff38e543. Report an issue: GitHub.

Appendix: source

Thrown at apps/meteor/app/apps/server/bridges/listeners.ts:443

				const [agentData] = args.payload;
				return this.orch
					.getManager()
					.getListenerManager()
					.executeListener(args.event, {
						room: (await this.orch.getConverters().get('rooms').convertRoom(agentData.room)) as IAppsLivechatRoom,
						agent: this.orch.getConverters().get('users').convertToApp(agentData.user),
					});

			case AppInterface.IPostLivechatRoomTransferred: {
				const [transferData] = args.payload;
				const converter = transferData.type === LivechatTransferEventType.AGENT ? 'users' : 'departments';

				const room = await this.orch.getConverters().get('rooms').convertById(transferData.room);
				const from = await this.orch.getConverters().get(converter).convertById(transferData.from);
				const to = await this.orch.getConverters().get(converter).convertById(transferData.to);

				if (!room) {
					throw new Error(`Room with id ${transferData.room} not found`);
				}

				if (!to) {
					throw new Error(`Transfer to entity with id ${transferData.to} not found`);
				}

				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: {

View on GitHub (pinned to b2c16d5842)