apereo/cas · error · FailedLoginException
Missing field 'total' from the query results for [username]
Error message
Missing field 'total' from the query results for [username]
What it means
When the query result does not contain the configured password field, the handler falls back to a 'total' row-count contract: the SQL must expose a column named 'total' counting matching users. If that column is absent, it throws FailedLoginException('Missing field 'total' from the query results for [username]').
Solutions
- Alias the count column exactly as total: SELECT COUNT(*) AS total FROM users WHERE username=?
- Verify sql config returns exactly one row containing 'total' when fieldPassword is not configured
- Check driver/alias casing and quote the alias if needed
- Alternatively configure fieldPassword to the real password column to use password comparison instead
Example fix
// before // cas.authn.jdbc.query[0].sql=SELECT COUNT(*) FROM users WHERE username=? // after // cas.authn.jdbc.query[0].sql=SELECT COUNT(*) AS total FROM users WHERE username=?
Defensive patterns
Strategy: validation
Validate before calling
Map<String,Object> row = jdbc.queryForMap(sql, user);
if (!row.containsKey("total")) throw new IllegalStateException("Auth SQL must expose COUNT(*) AS total when no password field is configured"); Try / catch
try {
authResult = handler.authenticate(credential);
} catch (FailedLoginException e) {
if (e.getMessage().contains("Missing field 'total'")) {
log.error("Auth SQL contract violated: add SELECT ... COUNT(*) AS total");
throw new ConfigurationException("Invalid cas.authn.jdbc.query sql"); // fail fast, this is a config bug
}
throw e;
} Prevention
- Always alias the count column exactly: SELECT COUNT(*) AS total
- Include the password column in the sql if you intend password comparison instead
- Validate the sql contract at deployment with an integration test
- Quote the alias to avoid driver case-folding
When it happens
Trigger: dbFields (single-row query result) lacks both properties.getFieldPassword() and the literal key 'total' — i.e. the SQL is neither a password-returning query nor a SELECT COUNT(*) AS total query.
Common situations: Misconfigured sql that selects neither password nor COUNT(*), column alias missing (SELECT COUNT(*) without 'AS total'), column alias upper-cased by the driver ('TOTAL' vs 'total'), query changed during migration.
Related errors
- Missing field value 'total' from the query results for…
- 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/3c2b8dccebe813ef.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-jdbc-authentication/src/main/java/org/apereo/cas/jdbc/QueryDatabaseAuthenticationHandler.java:68
@Override
protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(
final UsernamePasswordCredential credential, final String originalPassword) throws Throwable {
val username = credential.getUsername();
val password = credential.toPassword();
try {
val dbFields = query(credential);
if (dbFields.containsKey(properties.getFieldPassword())) {
val dbPassword = (String) dbFields.get(properties.getFieldPassword());
val originalPasswordMatchFails = StringUtils.isNotBlank(originalPassword) && !matches(originalPassword, dbPassword);
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");View on GitHub (pinned to e7288fc434)