RocketChat/Rocket.Chat · error · Meteor.Error

error-not-allowed

error-not-allowed

Error message

User participated in federation, this user can only be deactivated permanently

What it means

deleteUser throws error-not-allowed (method 'deleteUser') when isUserFederated(user) is true: the account has participated in federation and its identity is known to remote servers. Such users can only be deactivated, because deleting them would break federation references and remote history.

Solutions

  1. Deactivate instead of delete: setUserActive(userId, false) preserves the federation references
  2. If deletion is mandatory, first remove the federation participation (leave federated rooms/DMs, purge federation data with guidance from Rocket.Chat support) and confirm the flag clears
  3. Adjust offboarding automation to branch on the federated flag

Example fix

// before
await deleteUser(uid); // federated user -> error-not-allowed

// after
const user = await Users.findOneById(uid, { projections: { federated: 1 } });
if (isUserFederated(user)) {
  await setUserActive(uid, false); // deactivate only
} else {
  await deleteUser(uid);
}
Defensive patterns

Strategy: validation

Validate before calling

const user = await Users.findOneById(uid, { projections: { federated: 1 } });
if (user && isUserFederated(user)) {
  await setUserActive(uid, false); // federated users may only be deactivated
  return { deactivated: true };
}
await deleteUser(uid);

Type guard

const isFederatedUser = (u: { federated?: boolean | { federated?: boolean } } | null): boolean =>
  !!isUserFederated((u ?? {}) as IUser); // reuse server helper; flag shape varies

Try / catch

try {
  await deleteUser(uid);
} catch (e) {
  if (isMeteorErrorCode(e, 'error-not-allowed') && /federation/i.test(e.reason ?? '')) {
  	await setUserActive(uid, false); // fall back to deactivation
  }
}

Prevention

When it happens

Trigger: Deleting a user who has exchanged federated DMs or joined federated rooms (federation app/EE enabled) via admin UI or REST user.delete.

Common situations: Offboarding scripts that delete rather than deactivate; federation piloted then abandoned, leaving federated flags on users nobody remembers.

Related errors


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

Appendix: source

Thrown at apps/meteor/server/lib/users/deleteUser.ts:51

export async function deleteUser(userId: string, confirmRelinquish = false, deletedBy?: IUser['_id']): Promise<{ deletedRooms: string[] }> {
	if (userId === 'rocket.cat') {
		throw new Meteor.Error('error-action-not-allowed', 'Deleting the rocket.cat user is not allowed', {
			method: 'deleteUser',
			action: 'Delete_user',
		});
	}

	const user = await Users.findOneById(userId, {
		projection: { username: 1, avatarOrigin: 1, roles: 1, federated: 1 },
	});

	if (!user) {
		return { deletedRooms: [] };
	}

	if (isUserFederated(user)) {
		throw new Meteor.Error('error-not-allowed', 'User participated in federation, this user can only be deactivated permanently', {
			method: 'deleteUser',
		});
	}

	const subscribedRooms = await getSubscribedRoomsForUserWithDetails(userId);

	if (shouldRemoveOrChangeOwner(subscribedRooms) && !confirmRelinquish) {
		const rooms = await getUserSingleOwnedRooms(subscribedRooms);
		throw new Meteor.Error('user-last-owner', '', rooms);
	}

	let deletedRooms: string[] = [];
	// Users without username can't do anything, so there is nothing to remove
	if (user.username != null) {
		let userToReplaceWhenUnlinking: IUser | null = null;
		const nameAlias = i18n.t('Removed_User');
		deletedRooms = await relinquishRoomOwnerships(userId, subscribedRooms, true);

View on GitHub (pinned to b2c16d5842)