RocketChat/Rocket.Chat · error · Meteor.Error

e.message

Error message

e.message

What it means

Dynamic rethrow: Accounts.createUserAsync rejected with a non-Meteor plain Error, so registerUser wraps e.message as the error text with NO stable error code. Typical origins are lower-level failures such as MongoDB duplicate-key (E11000 on users email/username) or custom accounts-validateNewUser hooks throwing plain Errors. Because there is no 'error-...' code, callers must match on the message.

Source

Thrown at apps/meteor/server/meteor-methods/users/registerUser.ts:116

	await validateEmailDomain(formData.email);

	const userData = {
		email: trim(formData.email.toLowerCase()),
		password: formData.pass,
		...(formData.name?.trim() && { name: formData.name?.trim() }),
		reason: formData.reason,
	};

	let userId;
	try {
		userId = await Accounts.createUserAsync(userData);
	} catch (e) {
		if (e instanceof Meteor.Error) {
			throw e;
		}

		if (e instanceof Error) {
			throw new Meteor.Error(e.message);
		}

		throw new Meteor.Error(String(e));
	}

	const reason = trim(formData.reason);
	if (manuallyApproveNewUsers && reason) {
		await Users.setReason(userId, reason);
	}

	try {
		Accounts.sendVerificationEmail(userId, userData.email);
	} catch (error) {
		// throw new Meteor.Error 'error-email-send-failed', 'Error trying to send email: ' + error.message, { method: 'registerUser', message: error.message }
	}

	return userId;
};

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Inspect the wrapped message: 'E11000 duplicate key' means the email/username is taken - prompt the user and pre-check availability.
  2. Ensure custom onCreateUser/validateNewUser hooks throw Meteor.Error (with a code), not plain Error, so clients get a stable code.
  3. Disable the submit button while the call is in flight to prevent duplicate races.

Example fix

// before: hook throws a plain Error, surfaces as opaque code-less Meteor.Error
Accounts.validateNewUser(() => { throw new Error('bad domain'); });

// after: throw a coded Meteor.Error so registerUser rethrows it unchanged
Accounts.validateNewUser(() => {
  throw new Meteor.Error('error-invalid-email-domain', 'Email domain not allowed');
});
Defensive patterns

Strategy: try-catch

Validate before calling

const taken = await checkUsernameAvailability(username); // e.g. GET /api/v1/users.info?username=...
const emailTaken = await checkEmailAvailability(email);
if (taken || emailTaken) return showInlineError('Username or email already in use');

Type guard

const isMeteorError = (e: unknown, code?: string): e is Meteor.Error =>
  typeof e === 'object' && e !== null && 'error' in e && (code === undefined || (e as Meteor.Error).error === code);

Try / catch

try {
  await Meteor.callAsync('registerUser', formData);
} catch (e) {
  if (isMeteorError(e, 'error-user-registration-disabled')) { /* handled elsewhere */ }
  // code-less errors come from createUserAsync wrapping: inspect the message
  const detail = (e as Meteor.Error).reason ?? String((e as Meteor.Error).error);
  if (/E11000 duplicate key/i.test(detail)) showInlineError('Email or username already registered');
  else showError(detail);
}

Prevention

When it happens

Trigger: Registering with an email or username that collides at the Mongo index level (the accounts-base 'Email already exists' variant is a Meteor.Error and is rethrown unchanged; driver-level E11000 lands here); an accounts package hook or third-party plugin rejecting with `throw new Error(...)`.

Common situations: Double-submitted signup forms racing each other; custom username-normalization hooks throwing plain Errors; sharded/multi-instance deployments where the race window between check and insert widens.

Related errors


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