RocketChat/Rocket.Chat · error

Errors occurred while deleting an app user

Error message

Errors occurred while deleting an app user: ${err}

What it means

The users bridge wraps deleteUser for the app user; any failure of the deletion routine is rethrown as 'Errors occurred while deleting an app user: <inner error>'. The text after the colon carries the actual cause — commonly the server refusing to delete a user that still owns channels or has other active responsibilities.

Solutions

  1. Read the inner error text after the colon — it names the exact server-side refusal (e.g. rooms that must be transferred).
  2. Transfer ownership or delete the rooms the bot user owns, then retry the uninstall.
  3. If state is inconsistent (app record gone but user remains), remove the leftover app user manually and clean up before reinstalling.

Example fix

// before - uninstall fails opaquely
// after - surface the wrapped cause and act on it
try {
  await removeUser(user, appId);
} catch (err) {
  const reason = String(err).replace(/^Errors occurred while deleting an app user: /, '');
  // e.g. 'User owns rooms...' -> transfer/delete those rooms, then retry once
}
Defensive patterns

Strategy: try-catch

Try / catch

Catch, strip the wrapper prefix, and branch on the inner message: mentions rooms -> transfer/delete owned rooms then retry the uninstall once; anything else -> abort and surface to the admin.

Prevention

When it happens

Trigger: Uninstalling an app whose bot user is owner/creator of channels or has open livechat rooms; the underlying deleteUser routine throwing (rooms to transfer, last owner, db unreachable) during uninstall.

Common situations: App created channels during its lifetime that were never transferred or deleted; partially failed uninstalls leaving inconsistent state; uninstall racing other operations.

Related errors


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

Appendix: source

Thrown at apps/meteor/app/apps/server/bridges/users.ts:124

		}

		void notifyOnUserChangeById({ clientAction: 'inserted', id: user._id });

		return user._id;
	}

	protected async remove(user: IUser & { id: string }, appId: string): Promise<boolean> {
		this.orch.debugLog(`The App's user is being removed: ${appId}`);

		// It's actually not a problem if there is no App user to delete - just means we don't need to do anything more.
		if (!user) {
			return true;
		}

		try {
			await deleteUser(user.id);
		} catch (err) {
			throw new Error(`Errors occurred while deleting an app user: ${err}`);
		}

		return true;
	}

	protected async update(user: IUser & { id: string }, fields: Partial<IUser>, appId: string): Promise<boolean> {
		this.orch.debugLog(`The App ${appId} is updating a user`);

		if (!user) {
			throw new Error('User not provided');
		}

		const { status, statusText, ...updateFields } = fields;

		if (status) {
			await Presence.setStatus(user.id, status as UserStatus, statusText);
		} else if (typeof statusText === 'string') {
			await setStatusText(

View on GitHub (pinned to b2c16d5842)