{"record":{"id":"31433b5984b5b7df","repo":"apache/cassandra","slug":"auth-check-after-connection-closed","errorCode":null,"errorMessage":"Auth check after connection closed","messagePattern":"Auth check after connection closed","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"warning","filePath":"src/java/org/apache/cassandra/transport/messages/AuthUtil.java","lineNumber":68,"sourceCode":"     * @param queryState                      The current query state\n     * @param token                           The token provided in an {@link AuthResponse} from the client (or empty\n     *                                        if not handling an AuthResponse).\n     * @param messageToSendBasedOnNegotiation Determines what response to return on based on whether sasl negotiation\n     *                                        is complete (1st parameter) and the challenege token returned from the\n     *                                        negotiator (2nd parameter).\n     * @return the response to send back to the client.\n     */\n    static Response handleLogin(Connection connection, QueryState queryState, byte[] token,\n                                BiFunction<Boolean, byte[], Response> messageToSendBasedOnNegotiation)\n    {\n        IAuthenticator.SaslNegotiator negotiator = ((ServerConnection) connection).getSaslNegotiator(queryState);\n        try\n        {\n            // client-side timeout can disconnect while sitting in auth executor queue so (client default 12s)\n            // discard if connection closed anyway\n            if (!connection.channel().isActive())\n            {\n                throw new AuthenticationException(\"Auth check after connection closed\");\n            }\n            byte[] challenge = negotiator.evaluateResponse(token);\n            if (negotiator.isComplete())\n            {\n                AuthenticatedUser user = negotiator.getAuthenticatedUser();\n                queryState.getClientState().login(user);\n                ClientMetrics.instance.markAuthSuccess(user.getAuthenticationMode());\n                AuthEvents.instance.notifyAuthSuccess(queryState);\n                // authentication is complete, complete the authentication flow.\n                return messageToSendBasedOnNegotiation.apply(true, challenge);\n            }\n            else\n            {\n                // authentication is incomplete, continue the authentication flow.\n                return messageToSendBasedOnNegotiation.apply(false, challenge);\n            }\n        }\n        catch (AuthenticationException e)","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/transport/messages/AuthUtil.java#L50-L86","documentation":"AuthUtil.handleLogin queues the SASL token check on an executor; if the client disconnects while the request was waiting in that queue, the handler detects channel.isActive() == false and throws AuthenticationException(\"Auth check after connection closed\") instead of running the (now pointless) authentication. The comment notes the client default timeout (12s) can trigger this.","triggerScenarios":"Client-side authentication timeout (default ~12s) expires or the client closes the socket while the login task is still queued on the auth executor; the queued task then sees an inactive channel.","commonSituations":"Slow authentication (expensive authenticator, overloaded auth executor, slow credential backend like LDAP) causing clients to time out and disconnect; bursty login traffic exhausting the small auth thread pool.","solutions":["Increase the client's auth/login timeout above the server's expected authentication latency.","Increase the native transport auth executor capacity or reduce authenticator cost (cache credentials/LDAP lookups).","Check server logs for authentication latency and executor queue buildup.","On the client, retry authentication after reconnecting."],"exampleFix":"// before (client)\ncluster = Cluster.builder().addContactPoint(host).withCredentials(u, p).build();\n// after\ncluster = Cluster.builder().addContactPoint(host).withCredentials(u, p)\n    .withSocketOptions(new SocketOptions().setConnectTimeoutMillis(30000).setReadTimeoutMillis(30000)).build();","handlingStrategy":"retry","validationCode":"// client-side: ensure generous timeouts before login\nif (socket.getSoTimeout() < 30000) socket.setSoTimeout(30000);","typeGuard":null,"tryCatchPattern":"try { login(user, pass); } catch (AuthenticationException e) { if (e.getMessage().contains(\"connection closed\")) { reconnect(); retryLogin(user, pass); } else throw e; }","preventionTips":["Set client auth/read timeouts above expected authenticator latency","Monitor auth executor queue depth on the server","Keep credential backends (LDAP etc.) fast and cached"],"tags":["authentication","sasl","timeout","connection-lifecycle"],"backgroundTag":"authentication-required","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}