apereo/cas · error · FailedLoginException

Missing field value 'total' from the query results for…

Error message

Missing field value 'total' from the query results for [username] or value not parseable as a number

What it means

After finding the 'total' column, the handler validates it is a parseable number; if the value is null or NumberUtils.isCreatable fails, it throws FailedLoginException('Missing field value 'total' ... or value not parseable as a number'). This guards the count-based authentication contract.

Solutions

  1. Ensure the query computes a real numeric count (COUNT(*)) and never returns NULL for total
  2. Wrap with COALESCE: SELECT COALESCE(COUNT(*),0) AS total ...
  3. Inspect the query result manually to see what value 'total' carries
  4. Fix alias collisions where 'total' maps to a text column

Example fix

// before
// SELECT total FROM user_counts WHERE username=?  -- text column
// after
// SELECT COUNT(*) AS total FROM users WHERE username=?
Defensive patterns

Strategy: validation

Validate before calling

Object total = jdbc.queryForMap(sql, user).get("total");
if (total == null || !NumberUtils.isCreatable(total.toString()))
    throw new IllegalStateException("'total' must be a non-null numeric COUNT(*) value, got: " + total);

Type guard

boolean isNumericCount(Object v) { return v != null && NumberUtils.isCreatable(v.toString()); }

Try / catch

try {
    authResult = handler.authenticate(credential);
} catch (FailedLoginException e) {
    if (e.getMessage().contains("not parseable as a number")) {
        log.error("'total' column is null/non-numeric; fix SQL to COUNT(*) AS total");
        throw new ConfigurationException("Bad auth sql projection");
    }
    throw e;
}

Prevention

When it happens

Trigger: dbFields contains 'total' but its value is null, or its toString() is not numeric (e.g. empty string, 'NULL' literal, a non-numeric placeholder from the query).

Common situations: COALESCE/NULL result from an outer query, alias collides with a non-numeric column, driver returns the string 'NULL', SQL bug returns text instead of a count.

Related errors


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

Appendix: source

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

        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");
                }
            }
            if (StringUtils.isNotBlank(properties.getFieldExpired()) && dbFields.containsKey(properties.getFieldExpired())) {
                val dbExpired = dbFields.get(properties.getFieldExpired()).toString();
                if (BooleanUtils.toBoolean(dbExpired) || "1".equals(dbExpired)) {

View on GitHub (pinned to e7288fc434)