{"record":{"id":"12923fe36eb07b1b","repo":"apereo/cas","slug":"could-not-locate-account-for-username","errorCode":null,"errorMessage":"Could not locate account for ${username}","messagePattern":"Could not locate account for (.+?)","errorType":"exception","errorClass":"AccountNotFoundException","httpStatus":404,"severity":"error","filePath":"support/cas-server-support-rest-authentication/src/main/java/org/apereo/cas/adaptors/rest/RestAuthenticationHandler.java","lineNumber":95,"sourceCode":"\n        var response = (HttpResponse) null;\n        try {\n            val exec = HttpExecutionRequest\n                .builder()\n                .basicAuthUsername(credential.getUsername())\n                .basicAuthPassword(credential.toPassword())\n                .method(HttpMethod.valueOf(properties.getMethod().toUpperCase(Locale.ENGLISH)))\n                .url(SpringExpressionLanguageValueResolver.getInstance().resolve(properties.getUri()))\n                .httpClient(httpClient)\n                .build()\n                .withoutRetry();\n            response = HttpUtils.execute(exec);\n            val status = HttpStatus.resolve(Objects.requireNonNull(response).getCode());\n            return switch (Objects.requireNonNull(status)) {\n                case OK -> buildPrincipalFromResponse(credential, response);\n                case FORBIDDEN -> throw new AccountDisabledException(\"Could not authenticate forbidden account for \" + credential.getUsername());\n                case UNAUTHORIZED -> throw new FailedLoginException(\"Could not authenticate account for \" + credential.getUsername());\n                case NOT_FOUND -> throw new AccountNotFoundException(\"Could not locate account for \" + credential.getUsername());\n                case LOCKED -> throw new AccountLockedException(\"Could not authenticate locked account for \" + credential.getUsername());\n                case PRECONDITION_FAILED -> throw new AccountExpiredException(\"Could not authenticate expired account for \" + credential.getUsername());\n                case PRECONDITION_REQUIRED -> throw new AccountPasswordMustChangeException(\"Account password must change for \" + credential.getUsername());\n                default -> throw new FailedLoginException(\"Rest endpoint returned an unknown status code \" + status + \" for \" + credential.getUsername());\n            };\n        } finally {\n            HttpUtils.close(response);\n        }\n    }\n\n    protected AuthenticationHandlerExecutionResult buildPrincipalFromResponse(\n        final UsernamePasswordCredential credential,\n        final HttpResponse response) throws Throwable {\n        try {\n            try (val content = ((HttpEntityContainer) response).getEntity().getContent()) {\n                val result = IOUtils.toString(content, StandardCharsets.UTF_8);\n                LOGGER.debug(\"REST authentication response received: [{}]\", result);\n                val principalFromRest = MAPPER.readValue(result, Principal.class);","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-rest-authentication/src/main/java/org/apereo/cas/adaptors/rest/RestAuthenticationHandler.java#L77-L113","documentation":"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.","triggerScenarios":"authenticateUsernamePasswordInternal calls the REST endpoint, which responds 404; the switch maps NOT_FOUND -> AccountNotFoundException.","commonSituations":"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.","solutions":["Verify the user exists in the remote identity store","Check cas.authn.rest.url for typos or a missing/renamed path segment","Confirm the endpoint service is deployed and routed correctly (test with curl)","If your API signals unknown users differently (e.g. 200 with empty body), adapt the endpoint or use a custom handler"],"exampleFix":"// before\ncas.authn.rest.url=https://api.example.com/authenicate\n// after (typo fixed)\ncas.authn.rest.url=https://api.example.com/authenticate","handlingStrategy":"try-catch","validationCode":"// Sanity-check the configured URL resolves before auth flows run\nvar code = new URL(restAuthUrl).openConnection().connect(); // and inspect response code","typeGuard":"boolean isNotFound(HttpResponse r) { return r != null && r.getCode() == 404; }","tryCatchPattern":"try {\n    return restHandler.authenticate(credential);\n} catch (AccountNotFoundException e) {\n    LOGGER.info(\"Unknown user: {}\", e.getMessage());\n    throw e; // continue auth chain for other handlers if configured\n}","preventionTips":["Pin and smoke-test cas.authn.rest.url in deployment checks","Keep endpoint paths stable across API version upgrades","Distinguish real unknown-user 404s from routing 404s in endpoint logs","Register fallback handlers in the CAS auth chain for users not in the REST store"],"tags":["authentication","rest","http-404","user-not-found"],"backgroundTag":"user-not-found","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}