RocketChat/Rocket.Chat · error

Invalid user

Error message

Invalid user

What it means

When creating a private group, AppRoomBridge.createPrivateGroup resolves the creator with Users.findOneById(userId) and throws 'Invalid user' when no user document matches room.creator.id — unlike the channel/DM paths, the private-group creation method needs the full user object, so the creator must exist.

Solutions

  1. Verify the creator exists first (e.g. read.getUserById) before attempting to create the private group
  2. Prefer the current user from the execution context over persisted ids
  3. Re-fetch a fresh room/user reference instead of reusing long-lived cached objects
  4. Surface a clear app-level error instead of letting the bridge throw

Example fix

// before
const room = { type: RoomType.PRIVATE_GROUP, creator: { id: staleUserId }, name: 'ops' };
await app.getRocketChat().getChat().createRoom(room, members); // staleUserId deleted -> throws
// after
const creator = await this.read.getUserById(staleUserId);
if (!creator) throw new Error('creator no longer exists');
const room = { type: RoomType.PRIVATE_GROUP, creator, name: 'ops' };
await app.getRocketChat().getChat().createRoom(room, members);
Defensive patterns

Strategy: validation

Validate before calling

const creator = await this.read.getUserById(room.creator.id);
if (!creator) {
  throw new Error(`cannot create private group: creator ${room.creator.id} not found`);
}
await app.getRocketChat().getChat().createRoom({ ...room, creator }, members);

Try / catch

try {
  await app.getRocketChat().getChat().createRoom(room, members);
} catch (err) {
  if (err instanceof Error && err.message === 'Invalid user') {
    app.getLogger().warn('private group creator no longer exists');
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: room.creator.id references a deleted user; an app passes its own bot user id while the bot user is missing; creator id copied from stale cached data, a different workspace, or a federation/import mismatch.

Common situations: Users deleted between when the app captured the id and when it creates the group; dev databases reset while the app kept persisted creator ids; typos in hand-built creator objects.

Understand the failure class

Background: "User not found", "Invalid user", and "does not exist": what missing-user lookup errors mean across Rocket.Chat, LiteLLM, Phabricator, rustfs, and pnpm — this error's family across 10 libraries.

Related errors


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

Appendix: source

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

		delete extraData.t;
		delete extraData.ro;
		delete extraData.customFields;

		return extraData;
	}

	private async createChannel(userId: string, room: ICoreRoom, members: string[]): Promise<string> {
		return (await createChannelMethod(userId, room.name || '', members, room.ro, room.customFields, this.prepareExtraData(room))).rid;
	}

	private async createDirectMessage(userId: string, members: string[]): Promise<string> {
		return (await createDirectMessage(members, userId)).rid;
	}

	private async createPrivateGroup(userId: string, room: ICoreRoom, members: string[]): Promise<string> {
		const user = await Users.findOneById(userId);
		if (!user) {
			throw new Error('Invalid user');
		}
		return (await createPrivateGroupMethod(user, room.name || '', members, room.ro, room.customFields, this.prepareExtraData(room))).rid;
	}

	protected async getById(roomId: string, appId: string): Promise<IRoom> {
		this.orch.debugLog(`The App ${appId} is getting the roomById: "${roomId}"`);

		// #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed.
		const promise: Promise<IRoom | undefined> = this.orch.getConverters()?.get('rooms').convertById(roomId);
		return promise as Promise<IRoom>;
	}

	protected async getByName(roomName: string, appId: string): Promise<IRoom> {
		this.orch.debugLog(`The App ${appId} is getting the roomByName: "${roomName}"`);

		// #TODO: #AppsEngineTypes - Remove explicit types and typecasts once the apps-engine definition/implementation mismatch is fixed.
		const promise: Promise<IRoom | undefined> = this.orch.getConverters()?.get('rooms').convertByName(roomName);
		return promise as Promise<IRoom>;

View on GitHub (pinned to b2c16d5842)