RocketChat/Rocket.Chat · error · Meteor.Error

error-status-not-allowed

error-status-not-allowed

Error message

Invisible status is disabled

What it means

Thrown by POST /api/v1/users.setStatus when the effective status resolves to 'offline' while Accounts_AllowInvisibleStatusOption is false. Effective status is the requested status, falling back to user.statusDefault then 'online', so even a message-only update can trip this if the user's default status is offline. Code: error-status-not-allowed, method 'users.setStatus'.

Solutions

  1. Don't send status offline when the setting is off; omit status to keep current/default
  2. If invisible presence is required, have the admin enable Accounts_AllowInvisibleStatusOption
  3. Reset affected users' statusDefault away from offline before message-only updates
  4. Read the setting up front in multi-workspace clients

Example fix

// before
await sdk.post('users.setStatus', { status: 'offline', message: 'do not disturb' });
// after
await sdk.post('users.setStatus', { status: 'busy', message: 'do not disturb' });
Defensive patterns

Strategy: validation

Validate before calling

const allowInvisible = await getSetting('Accounts_AllowInvisibleStatusOption');
const effective = body.status ?? user.statusDefault ?? 'online';
if (effective === 'offline' && !allowInvisible) throw new Error('invisible status disabled');
await sdk.post('users.setStatus', body);

Type guard

const isStatusAllowed = (status: string, allowInvisible: boolean): status is 'online'|'busy'|'away'|'offline' => ['online','busy','away','offline'].includes(status) && (status !== 'offline' || allowInvisible);

Try / catch

try { await sdk.post('users.setStatus', body); } catch (e) { if (e.response?.data?.errorType === 'error-status-not-allowed') { body.status = 'busy'; await sdk.post('users.setStatus', body); } else throw e; }

Prevention

When it happens

Trigger: POST users.setStatus {"status":"offline"} with the setting disabled; message-only update for a user whose statusDefault is 'offline'; clients that mirror a chat-app 'invisible' mode onto Rocket.Chat status.

Common situations: Workspace policy requiring real presence; setting flipped after users already set offline defaults; federation/bridge tools syncing invisible state from another platform.

Related errors


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

Appendix: source

Thrown at apps/meteor/server/api/v1/users.ts:2075

			const statusExpiresAt = expiresAt ? new Date(expiresAt) : undefined;
			if (statusExpiresAt && Number.isNaN(statusExpiresAt.getTime())) {
				throw new Meteor.Error('error-invalid-date', 'Invalid expiresAt date string', {
					method: 'users.setStatus',
				});
			}

			if (statusExpiresAt && statusExpiresAt.getTime() <= Date.now()) {
				throw new Meteor.Error('error-invalid-date', 'expiresAt must be a future date', {
					method: 'users.setStatus',
				});
			}

			// If status is missing (message-only update), keep the user's chosen status (statusDefault),
			// not the computed status — otherwise a transient auto-away/offline gets pinned as a manual claim.
			const effectiveStatus = status || user.statusDefault || ('online' as UserStatus);

			if (effectiveStatus === 'offline' && !settings.get('Accounts_AllowInvisibleStatusOption')) {
				throw new Meteor.Error('error-status-not-allowed', 'Invisible status is disabled', {
					method: 'users.setStatus',
				});
			}

			await Presence.setStatus(user._id, effectiveStatus, message, statusExpiresAt);

			return API.v1.success();
		},
	)
	.get(
		'users.getStatus',
		{
			authRequired: true,
			query: isUsersGetStatusParamsGET,
			response: {
				200: ajv.compile<{ _id: string; status: string; connectionStatus?: string; statusSource?: string; statusExpiresAt?: string }>({
					type: 'object',
					properties: {

View on GitHub (pinned to e4b8178b20)