{"record":{"id":"921b664bd3543551","repo":"apache/hadoop","slug":"client-already-attempted-negotiation","errorCode":null,"errorMessage":"Client already attempted negotiation","messagePattern":"Client already attempted negotiation","errorType":"exception","errorClass":"AccessControlException","httpStatus":null,"severity":"critical","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java","lineNumber":2403,"sourceCode":"     * @param saslMessage received SASL message\n     * @return the sasl response to send back to client\n     * @throws SaslException if authentication or generating response fails, \n     *                       or SASL protocol mixup\n     * @throws IOException if a SaslServer cannot be created\n     * @throws AccessControlException if the requested authentication type \n     *         is not supported or trying to re-attempt negotiation.\n     * @throws InterruptedException\n     */\n    private RpcSaslProto processSaslMessage(RpcSaslProto saslMessage)\n        throws SaslException, IOException, AccessControlException,\n        InterruptedException {\n      final RpcSaslProto saslResponse;\n      final SaslState state = saslMessage.getState(); // required      \n      switch (state) {\n        case NEGOTIATE: {\n          if (sentNegotiate) {\n            // FIXME shouldn't this be SaslException?\n            throw new AccessControlException(\n                \"Client already attempted negotiation\");\n          }\n          saslResponse = buildSaslNegotiateResponse();\n          // simple-only server negotiate response is success which client\n          // interprets as switch to simple\n          if (saslResponse.getState() == SaslState.SUCCESS) {\n            switchToSimple();\n          }\n          break;\n        }\n        case INITIATE: {\n          if (saslMessage.getAuthsCount() != 1) {\n            throw new SaslException(\"Client mechanism is malformed\");\n          }\n          // verify the client requested an advertised authType\n          SaslAuth clientSaslAuth = saslMessage.getAuths(0);\n          if (!negotiateResponse.getAuthsList().contains(clientSaslAuth)) {\n            if (sentNegotiate) {","sourceCodeStart":2385,"sourceCodeEnd":2421,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java#L2385-L2421","documentation":"In processSaslMessage's NEGOTIATE case, a second NEGOTIATE on a connection where the server already sent its advertise list (sentNegotiate true) is rejected with AccessControlException(\"Client already attempted negotiation\") — the source even carries a FIXME noting SaslException might be more apt. The client restarted a handshake the server already answered.","triggerScenarios":"Client sends NEGOTIATE, then sends NEGOTIATE again on the same connection: retry-on-timeout logic that ignores the first response, duplicated frames from a proxy, or a custom client that loops the handshake.","commonSituations":"Custom clients resending negotiate on a timeout; transparent proxies duplicating requests; client/server version skew in SASL sequencing; replayed test fixtures.","solutions":["Send NEGOTIATE exactly once per connection and handle the server's response instead of resending.","If the negotiate response was lost, close the connection and start a new one — never renegotiate in place.","Use standard Hadoop RPC client stacks, which sequence the handshake correctly."],"exampleFix":"// before\nif (!negotiateResponseReceived && elapsed > timeout) {\n  sendNegotiate(); // duplicate NEGOTIATE -> AccessControlException\n}\n// after\nif (!negotiateResponseReceived && elapsed > timeout) {\n  conn.close();\n  conn = newConnection();\n  sendNegotiateOnce(conn);\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"Catch AccessControlException from the SASL exchange with 'already attempted' semantics as fatal for that connection: close it, open a new one, and send NEGOTIATE exactly once there.","preventionTips":["Send NEGOTIATE once per connection and always consume the server's response before acting.","On a lost/hung handshake, replace the connection rather than resending on it.","Beware of proxies or replay logic that can duplicate SASL frames."],"tags":["rpc","sasl","security","state-machine","retry"],"backgroundTag":"sasl-negotiation-failed","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}