n8n-io/n8n · warning · BadRequestError

SAML user may not change their email

Error message

SAML user may not change their email

What it means

A BadRequestError (HTTP 400) from validateChangingUserEmail when isSamlLicensedAndEnabled() is true. When SAML is licensed and active, email is the immutable key that maps a user to their IdP account, so email changes are blocked. Logged at debug with the userId and payload before throwing.

Source

Thrown at packages/cli/src/controllers/me.controller.ts:137

	private async validateChangingUserEmail(currentUser: User, payload: UserUpdateRequestDto) {
		if (!payload.email || payload.email === currentUser.email) {
			// email is not being changed
			return;
		}
		const { currentPassword: providedCurrentPassword, ...payloadWithoutPassword } = payload;
		const { id: userId, mfaEnabled } = currentUser;

		// If SAML is enabled, we don't allow the user to change their email address
		if (isSamlLicensedAndEnabled()) {
			this.logger.debug(
				'Request to update user failed because SAML user may not change their email',
				{
					userId: currentUser.id,
					payload: payloadWithoutPassword,
				},
			);
			throw new BadRequestError('SAML user may not change their email');
		}

		if (mfaEnabled) {
			if (!payload.mfaCode) {
				throw new BadRequestError('Two-factor code is required to change email');
			}

			const isMfaCodeValid = await this.mfaService.validateMfa(userId, payload.mfaCode, undefined);
			if (!isMfaCodeValid) {
				throw new InvalidMfaCodeError();
			}
		} else {
			if (currentUser.password === null) {
				this.logger.debug('User with no password changed their email', {
					userId: currentUser.id,
					payload: payloadWithoutPassword,
				});
				return;

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Change the user's email in the SAML Identity Provider; it will sync on next login.
  2. If SAML was enabled by mistake, disable it and restart n8n to allow email changes again.
  3. Have an admin update the email directly in the DB only if SAML mapping is also corrected.
Defensive patterns

Strategy: validation

Validate before calling

// Block email changes when SAML is active.
const { samlLicensedAndEnabled } = await api.get('/sso/config');
if (samlLicensedAndEnabled && payload.email !== me.email) {
  throw new Error('Email is managed by SAML — change it in the IdP.');
}

Type guard

function isEmailChange(p: { email?: string }, current: string): boolean {
  return typeof p.email === 'string' && p.email.toLowerCase() !== current.toLowerCase();
}

Try / catch

try {
  await api.patch('/me', payload);
} catch (e) {
  if (e.response?.status === 400 && /SAML user may not change their email/i.test(e.response.data.message)) {
    notify('Change your email in the SAML Identity Provider.');
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: PATCH /me where the email field differs from the current email, while the instance has SAML licensed and enabled. The check is the first guard inside validateChangingUserEmail.

Common situations: SAML-enabled instance where a user tries to change their email; admin enables SAML after users were accustomed to self-service email changes; IdP email mismatch the user tries to fix client-side.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/17fb25875586b9ff. Report an issue: GitHub.