RocketChat/Rocket.Chat · error · Meteor.Error

LDAP-login-error

LDAP-login-error

Error message

LDAP Authentication succeeded, but there's already an existing user with provided username [${user.username}] in Mongo.

What it means

Thrown by LDAP Manager.loginExistingUser when LDAP authentication succeeded but the matching local account was never marked as an LDAP user (user.ldap !== true) and the setting LDAP_Merge_Existing_Users is not enabled. Rocket.Chat refuses to silently convert a local password account into an LDAP-backed one, so login fails with Meteor.Error code 'LDAP-login-error'.

Source

Thrown at apps/meteor/server/lib/ldap/Manager.ts:345

	): Promise<void> {
		logger.debug('running onLDAPLogin');
		if (settings.get<boolean>('LDAP_Login_Fallback') && typeof password === 'string' && password.trim() !== '') {
			await Accounts.setPasswordAsync(user._id, password, { logout: false });
		}

		await this.syncUserAvatar(user, ldapUser);
		await callbacks.run('onLDAPLogin', { user, ldapUser, isNewUser }, ldap);
	}

	private static async loginExistingUser(
		ldap: LDAPConnection,
		user: IUser,
		ldapUser: ILDAPEntry,
		password?: string,
	): Promise<LDAPLoginResult> {
		if (user.ldap !== true && settings.get('LDAP_Merge_Existing_Users') !== true) {
			logger.debug('User exists without "ldap: true"');
			throw new Meteor.Error(
				'LDAP-login-error',
				`LDAP Authentication succeeded, but there's already an existing user with provided username [${user.username}] in Mongo.`,
			);
		}

		// If we're merging an ldap user with a local user, then we need to sync the data even if 'update data on login' is off.
		const forceUserSync = !user.ldap;

		const syncData = forceUserSync || (settings.get<boolean>('LDAP_Update_Data_On_Login') ?? true);
		logger.debug({ msg: 'Logging user in', syncData });
		const updatedUser = (syncData && (await this.syncUserForLogin(ldapUser, user))) || user;

		await this.onLogin(ldapUser, updatedUser, password, ldap, false);
		return {
			userId: user._id,
		};
	}

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Enable Admin -> LDAP -> Advanced -> 'Merge existing users' (LDAP_Merge_Existing_Users = true) so the existing account is adopted and flagged as ldap on next login
  2. Alternatively rename or delete the conflicting local account so the LDAP user is created fresh
  3. As the affected user, keep using local credentials until an admin resolves the collision

Example fix

// before — default settings
LDAP_Merge_Existing_Users = false  // local user 'jane' blocks LDAP login for 'jane'

// after
Admin -> LDAP -> Advanced -> Merge existing users = true
// next LDAP login syncs and flags the account; or rename the local account first
Defensive patterns

Strategy: try-catch

Validate before calling

// server-side pre-check before enabling LDAP for a workspace with local accounts
if (settings.get<boolean>('LDAP_Merge_Existing_Users') !== true) {
  // warn: any username existing as a non-LDAP local account will fail LDAP login
}

Try / catch

try {
  const result = await ldapLogin(username, password);
} catch (err) {
  if (err instanceof Meteor.Error && err.error === 'LDAP-login-error') {
    // LDAP bind succeeded but a local (non-ldap) account owns this username:
    // enable Admin -> LDAP -> 'Merge existing users', or rename/remove the local account
  }
  throw err;
}

Prevention

When it happens

Trigger: An employee first signs in via LDAP (SSO) using a username that already exists as a local account created earlier by registration, admin provisioning, or migration; their document lacks ldap: true and Admin -> LDAP -> 'Merge existing users' is off, so loginExistingUser throws after the bind succeeds.

Common situations: Companies rolling out LDAP/SAML after running Rocket.Chat with local accounts; provisioning scripts that pre-create accounts without the ldap flag; test users created manually before SSO was enabled; same username in both systems by coincidence.

Understand the failure class

Related errors


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