RocketChat/Rocket.Chat · error · Error

Username is required

Error message

Username is required

What it means

Client-side guard in the UsersInRole admin panel: when removing a user from a role, the handler receives the row's username and throws a plain Error 'Username is required' if it is falsy before calling POST /v1/roles.removeUserFromRole. The caught error is shown as a toast. It signals a UI/data defect — a role-membership row without a username — rather than a server problem.

Source

Thrown at apps/meteor/client/views/admin/permissions/UsersInRole/hooks/useRemoveUserFromRole.tsx:30

	roleDescription,
}: {
	rid?: IRoom['_id'];
	roleId: IRole['_id'];
	roleName: IRole['name'];
	roleDescription: IRole['description'];
}) => {
	const { t } = useTranslation();

	const setModal = useSetModal();
	const dispatchToastMessage = useToastMessageDispatch();
	const queryClient = useQueryClient();

	const removeUserFromRoleEndpoint = useEndpoint('POST', '/v1/roles.removeUserFromRole');

	const handleRemove = useStableCallback((username: IUserInRole['username']) => {
		const remove = async () => {
			try {
				if (!username) throw new Error('Username is required');

				await removeUserFromRoleEndpoint({ roleId, username, scope: rid });
				dispatchToastMessage({ type: 'success', message: t('User_removed') });
				queryClient.invalidateQueries({
					queryKey: ['getUsersInRole'],
				});
			} catch (error) {
				dispatchToastMessage({ type: 'error', message: error });
			} finally {
				setModal(null);
			}
		};

		setModal(
			<GenericModal variant='danger' onConfirm={remove} onCancel={() => setModal(null)} confirmText={t('Delete')}>
				{t('The_user_s_will_be_removed_from_role_s', { username, role: roleDescription || roleName })}
			</GenericModal>,
		);

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Inspect the getUsersInRole response for the offending row and fix the underlying data so username is present.
  2. Verify the component passes username (not name/userId) into handleRemove.
  3. If memberships without usernames are legitimate in your deployment, guard the UI earlier and hide the remove action for such rows.

Example fix

// before
if (!username) throw new Error('Username is required');

// after: prevent the broken row from offering 'remove'
const canRemove = Boolean(row.username);
<Table.Cell>{canRemove ? <RemoveButton username={row.username} /> : null}</Table.Cell>
Defensive patterns

Strategy: type-guard

Validate before calling

const rows = (await getUsersInRole({ roleId })).users;
const removable = rows.filter((r) => Boolean(r.username));

Type guard

const hasUsername = (row: IUserInRole): row is IUserInRole & { username: string } =>
  typeof row.username === 'string' && row.username.length > 0;

Try / catch

try { await handleRemove(row.username); } catch (e) { if ((e as Error).message === 'Username is required') { /* fix the row data, then retry */ return; } throw e; }

Prevention

When it happens

Trigger: Clicking 'remove' on a users-in-role table row whose username field is empty/undefined (data fetched from GET /v1/roles.getUsersInRole lacking username), or a programmatic call of handleRemove with no argument.

Common situations: Broken/incomplete REST payload for users-in-role (custom fields stripping username); corrupted membership documents; regressions in the table component passing the wrong property.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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