n8n-io/n8n · warning · UnprocessableRequestError

forgotPassword.ldapUserPasswordResetUnavailable

Error message

forgotPassword.ldapUserPasswordResetUnavailable

What it means

n8n refuses to send a password-reset email for a user whose identity is managed by LDAP. When the instance license has LDAP enabled (license.isLdapEnabled()) and the resolved user has an authIdentity with providerType 'ldap', the request is rejected with 422 UnprocessableRequestError because the user's credentials live in the directory server, not n8n's local store.

Source

Thrown at packages/cli/src/controllers/password-reset.controller.ts:124

				this.logger.debug(
					`Request to send password reset email failed because login is handled by ${currentAuthenticationMethod}`,
				);
				throw new ForbiddenError(
					`Login is handled by ${currentAuthenticationMethod}. Please contact your Identity Provider to reset your password.`,
				);
			}

			const ldapIdentity = user.authIdentities?.find((i) => i.providerType === 'ldap');
			if (!user.password || (ldapIdentity && user.disabled)) {
				this.logger.debug(
					'Request to send password reset email failed because no user was found for the provided email',
					{ invalidEmail: email },
				);
				return;
			}

			if (this.license.isLdapEnabled() && ldapIdentity) {
				throw new UnprocessableRequestError('forgotPassword.ldapUserPasswordResetUnavailable');
			}

			const url = this.authService.generatePasswordResetUrl(user);

			const { id, firstName } = user;
			try {
				await this.mailer.passwordReset({
					email,
					firstName,
					passwordResetUrl: url,
				});
			} catch (error) {
				this.eventService.emit('email-failed', {
					user,
					messageType: 'Reset password',
					publicApi: false,
				});
				if (error instanceof Error) {

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Reset the user's password in the LDAP/Active Directory server, since n8n does not own it.
  2. Confirm the user is expected to be LDAP-managed; if they should be local, remove the ldap authIdentity or re-provision.
  3. If LDAP is not actually in use, disable the LDAP license feature so isLdapEnabled() returns false.
Defensive patterns

Strategy: validation

Validate before calling

// Before calling forgot-password, check whether the target user is LDAP-managed.
// Pseudo caller-side check (requires a user lookup the caller already has):
function isLdapManaged(user) {
  return Boolean(user?.authIdentities?.some((i) => i.providerType === 'ldap'));
}
// if (isLdapManaged(user)) { route to directory password reset, do NOT call /forgot-password }

Type guard

function isLdapManaged(user) {
  return Boolean(
    user &&
    Array.isArray(user.authIdentities) &&
    user.authIdentities.some((i) => i && i.providerType === 'ldap'),
  );
}

Try / catch

try {
  await api.post('/forgot-password', { email });
} catch (e) {
  if (e.status === 422 && /ldapUserPasswordResetUnavailable/.test(e.message)) {
    // direct user to LDAP/directory reset instead of retrying
  } else { throw e; }
}

Prevention

When it happens

Trigger: POST to the forgot-password endpoint with an email that resolves to a user who has an 'ldap' authIdentity, while the instance is licensed for and running with LDAP enabled. The lookup path also short-circuits earlier (returns silently) when the user has no password or is disabled, so this throw only fires for an active LDAP user with an LDAP identity.

Common situations: SSO/LDAP deployments where some users are provisioned through the directory; an admin or user clicks 'Forgot password' in the UI for an account that is authenticated against LDAP rather than locally.

Related errors


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