RocketChat/Rocket.Chat · warning · Meteor.Error
error-user-already-in-role
error-user-already-in-role
Error message
User already in role
What it means
Thrown by POST roles.addUserToRole when hasRoleAsync(user._id, role._id, roomId) is already true. The role lookup succeeded and the user was resolved via getUserFromParams, but the user already holds the role (optionally scoped to roomId). Returns a structured Meteor.Error. Note earlier failures in this action use return API.v1.failure(...) instead of throwing.
Source
Thrown at apps/meteor/server/api/v1/roles.ts:144
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
},
},
async function action() {
const user = await getUserFromParams(this.bodyParams);
const { roleId, roomId } = this.bodyParams;
if (!roleId) {
return API.v1.failure('error-invalid-role-properties');
}
const role = await Roles.findOneById(roleId);
if (!role) {
return API.v1.failure('error-role-not-found', 'Role not found');
}
if (await hasRoleAsync(user._id, role._id, roomId)) {
throw new Meteor.Error('error-user-already-in-role', 'User already in role');
}
await addUserToRole(this.userId, role._id, user.username, roomId);
return API.v1.success({
role,
});
},
)
.get(
'roles.getUsersInRole',
{
authRequired: true,
permissionsRequired: ['access-permissions'],
query: isRolesGetUsersInRoleProps,
response: {
200: ajv.compile<{ users: IUserInRole[]; total: number }>({
type: 'object',View on GitHub (pinned to f9d3ec372b)
Solutions
- Treat the error as success for idempotent workflows (user is already in the desired state).
- Check membership first with GET /api/v1/roles.getUsersInRole before attempting the add.
- When scoping by roomId, verify whether the role is room-scoped before re-assigning.
Example fix
// before
await fetch('/api/v1/roles.addUserToRole', { method:'POST', body: JSON.stringify({ roleId, username }) });
// after - treat already-in-role as idempotent success
try {
await fetch('/api/v1/roles.addUserToRole', { method:'POST', body: JSON.stringify({ roleId, username }) });
} catch (e) {
if (e.error === 'error-user-already-in-role') return; // already desired state
throw e;
} Defensive patterns
Strategy: try-catch
Try / catch
try {
await fetch('/api/v1/roles.addUserToRole', { method:'POST', body: JSON.stringify({ roleId, username }) });
} catch (e) {
if (e.error === 'error-user-already-in-role') return; // idempotent success
throw e;
} Prevention
- Treat already-in-role as the desired end state in automation.
- For non-idempotent UIs, check membership first via roles.getUsersInRole.
When it happens
Trigger: POST /api/v1/roles.addUserToRole with a user+role (+optional roomId scope) combination that the user is already a member of; re-running an idempotent assignment.
Common situations: UI 'add to role' button clicked twice; automation re-applies role assignments; migration script re-granting existing roles.
Related errors
- error-user-not-in-role
- error-not-allowed
- error-role-in-use
- error-not-authorized
- error-action-not-allowed
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/21a6aacc1620292d.
Report an issue: GitHub.