RocketChat/Rocket.Chat · error · Meteor.Error
error-action-not-allowed
error-action-not-allowed
Error message
Editing user is not allowed
What it means
Thrown by the users.setPreferences endpoint when the caller supplies a bodyParams.userId that differs from their own authenticated userId and they lack the 'edit-other-user-info' permission.
Source
Thrown at apps/meteor/server/api/v1/users.ts:243
)
.post(
'users.setPreferences',
{
authRequired: true,
body: isUsersSetPreferencesParamsPOST,
response: {
200: userObjectResponse,
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
},
},
async function action() {
if (
this.bodyParams.userId &&
this.bodyParams.userId !== this.userId &&
!(await hasPermissionAsync(this.user, 'edit-other-user-info'))
) {
throw new Meteor.Error('error-action-not-allowed', 'Editing user is not allowed');
}
const userId = this.bodyParams.userId ? this.bodyParams.userId : this.userId;
if (!(await Users.findOneById(userId))) {
throw new Meteor.Error('error-invalid-user', 'The optional "userId" param provided does not match any users');
}
await saveUserPreferences(this.bodyParams.data, userId);
const user = await Users.findOneById(userId, {
projection: {
'settings.preferences': 1,
'language': 1,
},
});
if (!user) {
return API.v1.failure('User not found');
}
View on GitHub (pinned to f9d3ec372b)
Solutions
- Omit userId to edit your own preferences, or authenticate as a user holding edit-other-user-info.
- Grant the edit-other-user-info role to the caller if cross-user edits are intended.
- Confirm the userId you are sending is actually your own when self-editing.
Example fix
// before
await POST('users.setPreferences', { userId: otherUserId, data: prefs });
// after - self-edit (no permission needed)
await POST('users.setPreferences', { data: prefs }); Defensive patterns
Strategy: validation
Validate before calling
// Only send userId when editing another user AND you hold the permission
const targetUserId = (body.userId && body.userId !== me._id && hasRole('edit-other-user-info'))
? body.userId
: undefined;
await POST('users.setPreferences', { data: prefs, ...(targetUserId ? { userId: targetUserId } : {}) }); Type guard
null
Try / catch
try {
await POST('users.setPreferences', body);
} catch (e) {
if (isMeteorError(e, 'error-action-not-allowed')) {
// drop userId and retry as self-edit, or escalate permissions
} else { throw e; }
} Prevention
- Default to omitting userId; only add it when cross-user editing is explicitly authorized.
- Check the caller's permissions in the UI before exposing cross-user controls.
When it happens
Trigger: POST users.setPreferences with { userId: '<other-user>' } while the authenticated user does not have the edit-other-user-info permission.
Common situations: A non-admin client tries to update another user's preferences; permission role was removed; testing with a wrong token.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/3162458f29d65b14.
Report an issue: GitHub.