RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-email

error-invalid-email

Error message

Invalid email

What it means

setEmail trims the email argument and throws error-invalid-email when the result is empty. This is pure presence validation: it fires before domain validation (validateEmailDomain) and availability checks, and no email-format regex runs here. Only an empty or whitespace-only string reaches this branch.

Solutions

  1. Require a non-empty, trimmed email in the calling form/API layer before invoking setEmail.
  2. Add basic format validation (regex) client-side so blank/garbage input never reaches the server.
  3. If email is optional in your flow, skip the setEmail call entirely instead of passing an empty string.

Example fix

// before
await setEmail(userId, req.body.email || '');

// after
const email = (req.body.email ?? '').trim();
if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)) {
  throw new Meteor.Error('error-invalid-email', 'Invalid email');
}
await setEmail(userId, email);
Defensive patterns

Strategy: validation

Validate before calling

const email = (rawEmail ?? '').trim();
if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)) {
  throw new Meteor.Error('error-invalid-email', 'Invalid email', { field: 'email' });
}
await setEmail(userId, email);

Type guard

const isValidEmail = (value: string): boolean => /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(value.trim());

Prevention

When it happens

Trigger: setEmail(userId, '') or setEmail(userId, ' ') — a form submitted with a blank email field, an optional field mapped straight into the call, or null coerced to empty string.

Common situations: Admin UI allowing blank email submissions; JSON payload with "email": ""; copy-paste whitespace-only values; migration scripts writing '' for users with no address.

Related errors


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

Appendix: source

Thrown at apps/meteor/server/lib/users/setEmail.ts:58

		});
	}
};

export const setEmail = async function (
	userId: string,
	email: string,
	shouldSendVerificationEmail = true,
	verified = false,
	updater?: Updater<IUser>,
	session?: ClientSession,
) {
	email = email.trim();
	if (!userId) {
		throw new Meteor.Error('error-invalid-user', 'Invalid user', { function: '_setEmail' });
	}

	if (!email) {
		throw new Meteor.Error('error-invalid-email', 'Invalid email', { function: '_setEmail' });
	}

	await validateEmailDomain(email);

	const user = await Users.findOneById(userId, { session });
	if (!user) {
		throw new Meteor.Error('error-invalid-user', 'Invalid user', { function: '_setEmail' });
	}

	// User already has desired username, return
	if (user?.emails?.[0] && user.emails[0].address === email) {
		return user;
	}

	// Check email availability
	if (!(await checkEmailAvailability(email))) {
		throw new Meteor.Error('error-field-unavailable', `${email} is already in use :(`, {
			function: '_setEmail',

View on GitHub (pinned to b2c16d5842)