apereo/cas · error · AccountNotFoundException

Could not locate account for

Error message

Could not locate account for ${username}

What it means

RestAuthenticationHandler throws AccountNotFoundException when the remote REST authentication endpoint replies HTTP 404 NOT_FOUND. CAS treats this as 'no such user' rather than a password failure, which affects subsequent handler processing and lockout statistics.

Solutions

  1. Verify the user exists in the remote identity store
  2. Check cas.authn.rest.url for typos or a missing/renamed path segment
  3. Confirm the endpoint service is deployed and routed correctly (test with curl)
  4. If your API signals unknown users differently (e.g. 200 with empty body), adapt the endpoint or use a custom handler

Example fix

// before
cas.authn.rest.url=https://api.example.com/authenicate
// after (typo fixed)
cas.authn.rest.url=https://api.example.com/authenticate
Defensive patterns

Strategy: try-catch

Validate before calling

// Sanity-check the configured URL resolves before auth flows run
var code = new URL(restAuthUrl).openConnection().connect(); // and inspect response code

Type guard

boolean isNotFound(HttpResponse r) { return r != null && r.getCode() == 404; }

Try / catch

try {
    return restHandler.authenticate(credential);
} catch (AccountNotFoundException e) {
    LOGGER.info("Unknown user: {}", e.getMessage());
    throw e; // continue auth chain for other handlers if configured
}

Prevention

When it happens

Trigger: authenticateUsernamePasswordInternal calls the REST endpoint, which responds 404; the switch maps NOT_FOUND -> AccountNotFoundException.

Common situations: Username does not exist in the remote system; the endpoint URL path is wrong so every request 404s; a reverse proxy returned 404 because the backing service is down or routes changed after an upgrade.

Understand the failure class

Background: "User not found", "Invalid user", and "does not exist": what missing-user lookup errors mean across Rocket.Chat, LiteLLM, Phabricator, rustfs, and pnpm — this error's family across 10 libraries.

Related errors


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

Appendix: source

Thrown at support/cas-server-support-rest-authentication/src/main/java/org/apereo/cas/adaptors/rest/RestAuthenticationHandler.java:95

        var response = (HttpResponse) null;
        try {
            val exec = HttpExecutionRequest
                .builder()
                .basicAuthUsername(credential.getUsername())
                .basicAuthPassword(credential.toPassword())
                .method(HttpMethod.valueOf(properties.getMethod().toUpperCase(Locale.ENGLISH)))
                .url(SpringExpressionLanguageValueResolver.getInstance().resolve(properties.getUri()))
                .httpClient(httpClient)
                .build()
                .withoutRetry();
            response = HttpUtils.execute(exec);
            val status = HttpStatus.resolve(Objects.requireNonNull(response).getCode());
            return switch (Objects.requireNonNull(status)) {
                case OK -> buildPrincipalFromResponse(credential, response);
                case FORBIDDEN -> throw new AccountDisabledException("Could not authenticate forbidden account for " + credential.getUsername());
                case UNAUTHORIZED -> throw new FailedLoginException("Could not authenticate account for " + credential.getUsername());
                case NOT_FOUND -> throw new AccountNotFoundException("Could not locate account for " + credential.getUsername());
                case LOCKED -> throw new AccountLockedException("Could not authenticate locked account for " + credential.getUsername());
                case PRECONDITION_FAILED -> throw new AccountExpiredException("Could not authenticate expired account for " + credential.getUsername());
                case PRECONDITION_REQUIRED -> throw new AccountPasswordMustChangeException("Account password must change for " + credential.getUsername());
                default -> throw new FailedLoginException("Rest endpoint returned an unknown status code " + status + " for " + credential.getUsername());
            };
        } finally {
            HttpUtils.close(response);
        }
    }

    protected AuthenticationHandlerExecutionResult buildPrincipalFromResponse(
        final UsernamePasswordCredential credential,
        final HttpResponse response) throws Throwable {
        try {
            try (val content = ((HttpEntityContainer) response).getEntity().getContent()) {
                val result = IOUtils.toString(content, StandardCharsets.UTF_8);
                LOGGER.debug("REST authentication response received: [{}]", result);
                val principalFromRest = MAPPER.readValue(result, Principal.class);

View on GitHub (pinned to e7288fc434)