apereo/cas · error · FailedLoginException
No records found for user [username]
Error message
No records found for user [username]
What it means
Using the count-based contract, the handler throws FailedLoginException('No records found for user [username]') when the 'total' value parses but is not exactly 1. Only a single matching record authenticates; zero matches (unknown user) and multiple matches (bad schema) both land here.
Solutions
- Confirm the user exists if count is 0 (data or username problem)
- Deduplicate rows and enforce a unique constraint if count > 1
- Check the SQL WHERE clause matches exactly one row per user
- Add explicit AccountNotFoundException handling upstream if you need to distinguish 0 from >1
Example fix
// before: duplicates allowed // CREATE TABLE users(username VARCHAR(255), ...); // after // CREATE UNIQUE INDEX ux_users_username ON users(username);
Defensive patterns
Strategy: validation
Validate before calling
int total = jdbc.queryForObject("SELECT COUNT(*) FROM users WHERE username=?", Integer.class, user);
if (total != 1) throw new IllegalStateException("Expected exactly 1 user row for " + user + ", found " + total); Try / catch
try {
authResult = handler.authenticate(credential);
} catch (FailedLoginException e) {
if (e.getMessage().startsWith("No records found")) {
// 0 => unknown user, >1 => duplicates; both are data issues, return generic failure
audit.logNoSingleRecord(user);
throw new BadCredentialsException("Invalid credentials");
}
throw e;
} Prevention
- Enforce a unique constraint on the username column so total can never exceed 1
- Use COUNT(*) AS total in the sql exactly once
- Provision users before enabling login against this source
- Treat total!=1 alerts as data-integrity incidents
When it happens
Trigger: NumberUtils.createNumber(total.toString()).longValue() != 1 — typically COUNT(*) = 0 because no row matches the username, or > 1 because of duplicates.
Common situations: Unknown user (count 0), duplicate usernames without a unique constraint (count > 1), case-insensitive duplicates, wrong WHERE clause joining multiple rows.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- [username] not found with SQL query
- Principal attribute [
- [e.getMessage()]
- Password does not match value on record.
- Password has expired
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/ece2de7500d15efc.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-jdbc-authentication/src/main/java/org/apereo/cas/jdbc/QueryDatabaseAuthenticationHandler.java:79
val originalPasswordEquals = StringUtils.isBlank(originalPassword) && !Strings.CI.equals(password, dbPassword);
if (originalPasswordMatchFails || originalPasswordEquals) {
throw new FailedLoginException("Password does not match value on record.");
}
} else {
LOGGER.debug("Password field is not found in the query results. Checking for result count...");
if (!dbFields.containsKey("total")) {
throw new FailedLoginException("Missing field 'total' from the query results for " + username);
}
val count = dbFields.get("total");
if (count == null || !NumberUtils.isCreatable(count.toString())) {
throw new FailedLoginException("Missing field value 'total' from the query results for "
+ username + " or value not parseable as a number");
}
val number = NumberUtils.createNumber(count.toString());
if (number.longValue() != 1) {
throw new FailedLoginException("No records found for user " + username);
}
}
if (StringUtils.isNotBlank(properties.getFieldDisabled()) && dbFields.containsKey(properties.getFieldDisabled())) {
val dbDisabled = dbFields.get(properties.getFieldDisabled()).toString();
if (BooleanUtils.toBoolean(dbDisabled) || "1".equals(dbDisabled)) {
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);View on GitHub (pinned to e7288fc434)