RocketChat/Rocket.Chat · error

There must be a parent room to create a discussion.

Error message

There must be a parent room to create a discussion.

What it means

Thrown by the Rocket.Chat apps-engine rooms bridge when an app calls createDiscussion and the converted room object has no prid (parent room id), or the prid does not match any room in the database. Discussions in Rocket.Chat always live inside an existing parent channel, so both conditions are hard requirements. The check runs before the server-side createDiscussion is invoked.

Solutions

  1. Set room.prid to the _id of an existing parent room, fetched fresh via the room reader right before creating the discussion.
  2. Re-verify the parent room exists if the discussion flow is long-lived (wizard-style UI) and re-fetch its id when stale.
  3. If the parent was deleted, pick another parent room or report to the user instead of retrying with the same prid.

Example fix

// before
const room: IRoom = { ...newRoom, fname: 'Weekly sync' }; // no prid
await createDiscussion(room, parentMessage, reply, members, appId);

// after
const parent = await this.read.getRoomReader().getById(context.getRoom().id);
if (!parent) {
  throw new Error('Parent room is gone; cannot create discussion');
}
const room: IRoom = { ...newRoom, prid: parent.id, fname: 'Weekly sync' };
await createDiscussion(room, parentMessage, reply, members, appId);
Defensive patterns

Strategy: validation

Validate before calling

const parent = room.prid ? await this.read.getRoomReader().getById(room.prid) : null;
if (!parent) {
  // abort: discussion requires an existing parent room
  throw new Error('Parent room does not exist');
}

Type guard

const hasParentRoomId = (room: IRoom): room is IRoom & { prid: string } =>
  typeof room.prid === 'string' && room.prid.length > 0;

Try / catch

Catch per call and surface a user-facing message ('discussions need an existing parent channel'); do not retry with the same prid.

Prevention

When it happens

Trigger: App invokes the rooms bridge createDiscussion with a room whose prid is undefined/empty, or whose prid points to a deleted or never-existing room (stale room id, or prid accidentally set to the new discussion's own id).

Common situations: Apps building the discussion room object by hand instead of deriving it from the parent; parent channel deleted between the read and the create; field-name mistakes (parentId or rid instead of prid).

Related errors


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

Appendix: source

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

	protected async createDiscussion(
		room: IRoom,
		parentMessage: IMessage | undefined = undefined,
		reply: string | undefined = '',
		members: Array<string> = [],
		appId: string,
	): Promise<string> {
		this.orch.debugLog(`The App ${appId} is creating a new discussion.`, room);

		const rcRoom = await this.orch.getConverters()?.get('rooms').convertAppRoom(room);

		let rcMessage;
		if (parentMessage) {
			rcMessage = await this.orch.getConverters()?.get('messages').convertAppMessage(parentMessage);
		}

		if (!rcRoom.prid || !(await Rooms.findOneById(rcRoom.prid))) {
			throw new Error('There must be a parent room to create a discussion.');
		}

		// #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed.
		const discussion = {
			prid: rcRoom.prid,
			t_name: rcRoom.fname as string,
			pmid: rcMessage ? rcMessage._id : undefined,
			reply: reply && reply.trim() !== '' ? reply : undefined,
			users: members.length > 0 ? members : [],
		};

		const { rid } = await createDiscussion(room.creator.id, discussion);

		return rid;
	}

	protected getModerators(roomId: string, appId: string): Promise<IUser[]> {
		this.orch.debugLog(`The App ${appId} is getting room moderators for room id: ${roomId}`);

View on GitHub (pinned to b2c16d5842)