RocketChat/Rocket.Chat · error · 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 Apps Engine room bridge's createDiscussion when an app tries to create a discussion whose room has no parent room id (prid) or whose prid does not resolve to an existing room. Rocket.Chat discussions are threaded conversations that must be anchored to a parent channel/group, so the bridge verifies the parent exists in the database before delegating to createDiscussion.

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 f9d3ec372b)

Solutions

  1. Set room.prid to the _id of a real parent channel/group/private-team before calling createDiscussion.
  2. Look up the parent room first (e.g. read.getRoomById) and validate it exists and the app can access it before creating the discussion.
  3. Guard the call with a try/catch and surface a user-facing message instead of crashing the app flow when the parent is gone.

Example fix

// before
const room: IRoom = { ...sharedRoomFields };
await modify.getCreator().startDiscussion(room, msg).setDisplayName('Thread').create();

// after
const parent = await read.getRoomReader().getById(parentRoomId);
if (!parent) {
  // bail out gracefully
  return;
}
const room: IRoom = { ...sharedRoomFields, prid: parent.id } as any;
await modify.getCreator().startDiscussion(room, msg).setDisplayName('Thread').create();
Defensive patterns

Strategy: validation

Validate before calling

const parent = await read.getRoomReader().getById(room.prid);
if (!parent) {
  throw new Error('Cannot create discussion: parent room does not exist');
}

Type guard

function hasValidParent(room: IRoom): room is IRoom & { prid: string } {
  return typeof room.prid === 'string' && room.prid.length > 0;
}

Try / catch

try {
  await modify.getCreator().startDiscussion(room, msg).create();
} catch (err) {
  if (err instanceof Error && err.message.includes('parent room')) {
    // parent missing or deleted — handle gracefully
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: An app calls createDiscussion with an IRoom whose prid is undefined/empty, or with a prid that points to a room that was deleted or never existed. The check is `!rcRoom.prid || !(await Rooms.findOneById(rcRoom.prid))`.

Common situations: App author forgets to set room.prid; copies a room object from a channel read but strips prid; parent room is deleted in the window between the app reading it and creating the discussion; prid is mistyped or taken from the wrong field.

Related errors


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