RocketChat/Rocket.Chat · error · Meteor.Error

error-creating-custom-user-status

error-creating-custom-user-status

Error message

Error creating custom user status

What it means

Thrown by POST custom-user-status.create as a post-condition check: after insertOrUpdateUserStatus runs, the endpoint re-reads CustomUserStatus.findOneByName(name) and throws Meteor.Error('error-creating-custom-user-status') if the status cannot be found. In practice insertOrUpdateUserStatus can return without creating/updating (for example when a status with the same name in a different case already exists), so the read-back misses and this fires.

Solutions

  1. List existing statuses first (GET /api/v1/custom-user-status.list) and skip creation when the name already exists case-insensitively.
  2. Normalize the name before sending (trim; decide one casing policy).
  3. If creation genuinely should have worked, check server logs for insert errors and retry with a distinct name.

Example fix

// before
await api.post('custom-user-status.create', { name, statusType });

// after — de-duplicate against existing statuses (case-insensitive)
const { statuses } = await api.get('custom-user-status.list');
if (!statuses.some(s => s.name.toLowerCase() === name.trim().toLowerCase())) {
  await api.post('custom-user-status.create', { name: name.trim(), statusType });
}
Defensive patterns

Strategy: validation

Validate before calling

async function createStatusIfAbsent(api, name: string, statusType: string) {
  const { statuses } = await api.get('custom-user-status.list');
  const exists = statuses.some(s => s.name.toLowerCase() === name.trim().toLowerCase());
  if (!exists) await api.post('custom-user-status.create', { name: name.trim(), statusType });
}

Try / catch

try { await api.post('custom-user-status.create', { name, statusType }); }
catch (e) {
  if (e.error === 'error-creating-custom-user-status') { await refreshStatuses(); /* likely duplicate-name guard */ } else throw e;
}

Prevention

When it happens

Trigger: POSTing { "name": "Busy", "statusType": "busy" } when a status named 'busy'/'BUSY' already exists (case-insensitive duplicate blocked inside insertOrUpdateUserStatus); name that normalizes to an existing entry; or the insert failing validation.

Common situations: Admin tooling that seeds statuses on every deploy and hits the duplicate-name guard; names differing only by case or surrounding whitespace; retries after a partially completed first request.

Related errors


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

Appendix: source

Thrown at apps/meteor/server/api/v1/custom-user-status.ts:171

		body: isCustomUserStatusCreateProps,
		response: {
			200: customUserStatusCreateResponseSchema,
			400: validateBadRequestErrorResponse,
			401: validateUnauthorizedErrorResponse,
			403: validateForbiddenErrorResponse,
		},
	},
	async function action() {
		const userStatusData = {
			name: this.bodyParams.name,
			statusType: this.bodyParams.statusType || '',
		};

		await insertOrUpdateUserStatus(this.userId, userStatusData);

		const customUserStatus = await CustomUserStatus.findOneByName(userStatusData.name);
		if (!customUserStatus) {
			throw new Meteor.Error('error-creating-custom-user-status', 'Error creating custom user status');
		}

		return API.v1.success({
			customUserStatus,
		});
	},
);

const isCustomUserStatusDeleteProps = ajv.compile<{ customUserStatusId: string }>({
	type: 'object',
	properties: {
		customUserStatusId: { type: 'string', minLength: 1 },
	},
	required: ['customUserStatusId'],
	additionalProperties: false,
});

const customUserStatusDeleteResponseSchema = ajv.compile<void>({

View on GitHub (pinned to b2c16d5842)