{"record":{"id":"cdeb940049159fcf","repo":"apereo/cas","slug":"rest-endpoint-returned-an-unknown-status-code-st","errorCode":null,"errorMessage":"Rest endpoint returned an unknown status code ${status} for ${username}","messagePattern":"Rest endpoint returned an unknown status code (.+?) for (.+?)","errorType":"exception","errorClass":"FailedLoginException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-rest-authentication/src/main/java/org/apereo/cas/adaptors/rest/RestAuthenticationHandler.java","lineNumber":99,"sourceCode":"                .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);\n                val principal = principalFactory.createPrincipal(principalFromRest.getId(), principalFromRest.getAttributes());\n                return createHandlerResult(credential, principal, getWarnings(response));\n            }\n        } catch (final Throwable e) {","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-rest-authentication/src/main/java/org/apereo/cas/adaptors/rest/RestAuthenticationHandler.java#L81-L117","documentation":"RestAuthenticationHandler throws FailedLoginException with the message 'Rest endpoint returned an unknown status code ...' when the endpoint replies with any HTTP status not explicitly handled by the switch (not 200/401/403/404/423/412/428) or a status that cannot be resolved. CAS fails safe: unrecognized outcomes are treated as failed logins with the raw status recorded in the message.","triggerScenarios":"authenticateUsernamePasswordInternal receives a status like 500, 502, 503, 429, 301, or an unresolvable code from the REST endpoint, falling into the default branch.","commonSituations":"The endpoint service is crashing or misconfigured (5xx); a gateway/load balancer intercepts requests (502/503); rate limiting returns 429; a redirect (3xx) from a mis-URL'd endpoint; TLS or proxy layers returning unexpected codes.","solutions":["Read the status code in the message and check the endpoint's logs for that response","Fix the endpoint/outage producing the unexpected status (5xx, 502/503 gateway issues)","Verify cas.authn.rest.url points directly at the authentication endpoint with no redirecting proxy","Handle known-but-unmapped codes (e.g. 429 rate limiting) on the endpoint side or via a custom handler"],"exampleFix":"// before\ncurl https://api.example.com/auth  ->  502 Bad Gateway\n// after fixing upstream service\ncurl https://api.example.com/auth  ->  200 OK","handlingStrategy":"retry","validationCode":"// Health-check the endpoint before routing auth traffic\nvar code = new URL(restAuthUrl).openConnection().connect(); // verify reachable, no redirects/5xx","typeGuard":"boolean isHandledStatus(HttpResponse r) {\n    return r != null && Set.of(200, 401, 403, 404, 412, 423, 428)\n        .contains(r.getCode());\n}","tryCatchPattern":"try {\n    return restHandler.authenticate(credential);\n} catch (FailedLoginException e) {\n    if (e.getMessage().contains(\"unknown status code\")) {\n        LOGGER.error(\"REST auth endpoint unhealthy: {}\", e.getMessage());\n        // page ops / consider circuit breaker before failing user login\n    }\n    throw e;\n}","preventionTips":["Add endpoint health checks and alerting for 5xx responses","Point cas.authn.rest.url directly at the auth endpoint, avoiding redirecting gateways","Map expected-but-unhandled codes (429, 302) on the endpoint side","Record the status code from the message to speed triage"],"tags":["authentication","rest","unexpected-http-status","fail-safe"],"backgroundTag":"unexpected-http-status","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"}