apereo/cas · error · FailedLoginException

Multiple records found for [username]

Error message

Multiple records found for [username]

What it means

When IncorrectResultSizeDataAccessException reports more than one row (actualSize > 1), the handler throws FailedLoginException 'Multiple records found'. The query is expected to return exactly one row per username; duplicates make identity ambiguous so login is refused.

Solutions

  1. Deduplicate rows: SELECT username, COUNT(*) FROM users GROUP BY username HAVING COUNT(*)>1, then remove/disable extras.
  2. Add a UNIQUE index on the username column to prevent recurrence.
  3. Refine the SQL to disambiguate (extra WHERE condition, status=active filter).
  4. Fix upstream provisioning that created the duplicate account.

Example fix

// before: no constraint, duplicates possible
// after
DELETE FROM users WHERE id NOT IN (SELECT MIN(id) FROM users GROUP BY username);
ALTER TABLE users ADD CONSTRAINT uq_users_username UNIQUE (username);
Defensive patterns

Strategy: validation

Validate before calling

List<String> dupes = jdbcTemplate.queryForList(
  "SELECT username FROM users GROUP BY username HAVING COUNT(*)>1", String.class);
if (!dupes.isEmpty()) { throw new IllegalStateException("Duplicate usernames: " + dupes); }

Try / catch

try { result = handler.authenticate(credential); }
catch (FailedLoginException e) { if (e.getMessage().startsWith("Multiple records")) { alertDataIntegrity(); } }

Prevention

When it happens

Trigger: sqlFindByUsername matches 2+ rows for the submitted username because the username column is not unique in the table.

Common situations: Missing UNIQUE constraint on the username column after data import; soft-deleted duplicate rows; username colliding across tenants in a shared table.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/9fbace52c4f27e93. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-jdbc-authentication/src/main/java/org/apereo/cas/jdbc/QueryDatabaseAuthenticationHandler.java:104

                    throw new AccountDisabledException("Account has been disabled");
                }
            }
            if (StringUtils.isNotBlank(properties.getFieldExpired()) && dbFields.containsKey(properties.getFieldExpired())) {
                val dbExpired = dbFields.get(properties.getFieldExpired()).toString();
                if (BooleanUtils.toBoolean(dbExpired) || "1".equals(dbExpired)) {
                    throw new AccountPasswordMustChangeException("Password has expired");
                }
            }

            val attributes = collectPrincipalAttributes(dbFields);
            val principal = this.principalFactory.createPrincipal(username, attributes);
            return createHandlerResult(credential, principal, new ArrayList<>());

        } catch (final IncorrectResultSizeDataAccessException e) {
            if (e.getActualSize() == 0) {
                throw new AccountNotFoundException(username + " not found with SQL query");
            }
            throw new FailedLoginException("Multiple records found for " + username);
        } catch (final DataAccessException e) {
            throw new PreventedException(e);
        }
    }

    protected Map<String, Object> query(final UsernamePasswordCredential credential) {
        val sql = SpringExpressionLanguageValueResolver.getInstance().resolve(properties.getSql());
        if (sql.contains("?")) {
            return getJdbcTemplate().queryForMap(sql, credential.getUsername());
        }
        val parameters = new LinkedHashMap<String, Object>();
        parameters.put("username", credential.getUsername());
        parameters.put("password", credential.toPassword());
        return getNamedParameterJdbcTemplate().queryForMap(sql, parameters);
    }
}

View on GitHub (pinned to e7288fc434)