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

  1. Omit userId to edit your own preferences, or authenticate as a user holding edit-other-user-info.
  2. Grant the edit-other-user-info role to the caller if cross-user edits are intended.
  3. 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

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.