RocketChat/Rocket.Chat · error · Meteor.Error
error-action-not-allowed
error-action-not-allowed
Error message
Editing settings is not allowed
What it means
The bulk `saveSettings` Meteor method throws `error-action-not-allowed` when `Meteor.userId()` is null — the caller is not authenticated. Note the error metadata misleadingly reports `method: 'saveSetting'` (single) even though the failing method is `saveSettings`; the method is also deprecated since 9.0.0 in favor of REST `POST /v1/settings`.
Solutions
- Wait for authentication: only call `saveSettings` once `Meteor.userId()` is non-null.
- Use the REST endpoint `POST /api/v1/settings` with an auth token for headless/programmatic settings updates.
- On reconnect, re-run the login flow and then retry the batch.
- When debugging, remember the reported method name 'saveSetting' is a copy-paste artifact — the failing call is the bulk method.
Example fix
// before
Meteor.call('saveSettings', [{ _id, value }]);
// after
if (Meteor.userId() === null) {
// wait for login before flushing pending settings changes
return;
}
Meteor.call('saveSettings', [{ _id, value }]); Defensive patterns
Strategy: validation
Validate before calling
if (Meteor.userId() === null) {
// defer the batch until after login
return;
}
await Meteor.callAsync('saveSettings', params); Type guard
const isAuthenticated = (): boolean => Meteor.userId() !== null;
Try / catch
try {
await Meteor.callAsync('saveSettings', params);
} catch (e: any) {
if (e?.error === 'error-action-not-allowed' && Meteor.userId() === null) {
// authentication failure: note the reported method name is 'saveSetting' (copy-paste)
}
} Prevention
- Queue settings changes until the login reactive state confirms a session.
- Use POST /api/v1/settings with tokens for headless clients.
- Watch for logged-out duplicate tabs sharing stale method calls.
When it happens
Trigger: Calling `Meteor.call('saveSettings', [{ _id, value }, ...])` from an unauthenticated DDP connection: before login completes, after logout, after an expired resume token reconnect, or from server code without a user context.
Common situations: Settings forms submitted during page load before the login reactive chain finishes; tokens invalidated server-side while the client keeps the connection; scripts calling the DDP method directly without establishing a session.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/a760807e9c2e5735.
Report an issue: GitHub.
Appendix: source
Thrown at apps/meteor/server/meteor-methods/settings/saveSettings.ts:33
_id: ISetting['_id'];
value: ISetting['value'];
}[],
): Promise<boolean>;
}
}
Meteor.methods<ServerMethods>({
saveSettings: twoFactorRequired(async function (
params: {
_id: ISetting['_id'];
value: ISetting['value'];
}[] = [],
) {
methodDeprecationLogger.method('saveSettings', '9.0.0', '/v1/settings');
const uid = Meteor.userId();
if (uid === null) {
throw new Meteor.Error('error-action-not-allowed', 'Editing settings is not allowed', {
method: 'saveSetting',
});
}
try {
await saveSettingsBulk(uid, params, {
username: (await Meteor.userAsync())!.username!,
ip: this.connection.clientAddress || '',
useragent: this.connection.httpHeaders['user-agent'] || '',
});
} catch (error) {
if (error instanceof SettingValidationError) {
throw new Meteor.Error('error-setting-validation-failed', error.message);
}
throw error;
}
return true;View on GitHub (pinned to b2c16d5842)