RocketChat/Rocket.Chat · error · Meteor.Error

error-could-not-change-email

error-could-not-change-email

Error message

Could not change email

What it means

A legacy guard: thrown when setEmail(user._id, email) from server/lib/users/setEmail.ts returns falsy. In the current implementation setEmail either throws a specific error (error-invalid-email, error-field-unavailable when the address is taken, domain-blocked errors from validateEmailDomain, error-email-send-failed) or returns a truthy user object - so this branch is effectively dead code, and real failures surface as those sibling error codes instead.

Source

Thrown at apps/meteor/server/meteor-methods/users/setEmail.ts:33

	}
}

export const setEmailFunction = async (email: string, user: Meteor.User | IUser) => {
	check(email, String);

	if (!settings.get('Accounts_AllowEmailChange')) {
		throw new Meteor.Error('error-action-not-allowed', 'Changing email is not allowed', {
			method: 'setEmail',
			action: 'Changing_email',
		});
	}

	if (user.emails?.[0]?.address === email) {
		return email;
	}

	if (!(await setEmail(user._id, email))) {
		throw new Meteor.Error('error-could-not-change-email', 'Could not change email', {
			method: 'setEmail',
		});
	}

	return email;
};

Meteor.methods<ServerMethods>({
	async setEmail(email) {
		methodDeprecationLogger.method('setEmail', '9.0.0', '/v1/users.updateOwnBasicInfo');
		const user = await Meteor.userAsync();

		if (!user) {
			throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'setEmail' });
		}

		return setEmailFunction(email, user);
	},

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Catch and switch on the actual Meteor.Error code - most often error-field-unavailable (email taken) or a domain-validation error
  2. Verify the new address is not used by another account first (GET /api/v1/users.info?username= or email lookup) before submitting
  3. Treat error-could-not-change-email as an unexpected-state fallback and log err.details for diagnosis

Example fix

// before
if (err.error === 'error-could-not-change-email') showError('Could not change email');

// after
switch (err.error) {
  case 'error-field-unavailable': showError('Email already in use'); break;
  case 'error-invalid-email': showError('Invalid email'); break;
  case 'error-email-send-failed': showError('Notification email failed'); break;
  default: showError('Could not change email');
}
Defensive patterns

Strategy: try-catch

Validate before calling

// avoid the common cause: check the address is not used by another account first
// GET /api/v1/users.info?userId=... or a directory search before submitting the change

Try / catch

catch (err) {
  if (!(err instanceof Meteor.Error)) throw err;
  switch (err.error) {
    case 'error-could-not-change-email': logUnexpected(err.details); break; // legacy/defensive
    case 'error-field-unavailable': showFieldError('email', 'Email already in use'); break;
    case 'error-invalid-email': showFieldError('email', 'Invalid email'); break;
    default: throw err;
  }
}

Prevention

When it happens

Trigger: Effectively unreachable with current server code. Historically covered a generic update failure; today a failing setEmailFunction call surfaces error-field-unavailable (email already in use), a blocked-domain error, or an SMTP failure instead.

Common situations: Client code written against old behavior that branches on error-could-not-change-email; the actual thrown code differs, so error handling silently misses; documentation copied from legacy wikis.

Related errors


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