{"record":{"id":"cac5199d98d1bfdd","repo":"apache/hadoop","slug":"client-sent-unsupported-state-state","errorCode":null,"errorMessage":"Client sent unsupported state ${state}","messagePattern":"Client sent unsupported state (.+?)","errorType":"exception","errorClass":"SaslException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java","lineNumber":2449,"sourceCode":"          // SIMPLE is a legit option above.  we will send no response\n          if (authMethod == AuthMethod.SIMPLE) {\n            switchToSimple();\n            saslResponse = null;\n            break;\n          }\n          // sasl server for tokens may already be instantiated\n          if (saslServer == null || authMethod != AuthMethod.TOKEN) {\n            saslServer = createSaslServer(authMethod);\n          }\n          saslResponse = processSaslToken(saslMessage);\n          break;\n        }\n        case RESPONSE: {\n          saslResponse = processSaslToken(saslMessage);\n          break;\n        }\n        default:\n          throw new SaslException(\"Client sent unsupported state \" + state);\n      }\n      return saslResponse;\n    }\n\n    private RpcSaslProto processSaslToken(RpcSaslProto saslMessage)\n        throws SaslException {\n      if (!saslMessage.hasToken()) {\n        throw new SaslException(\"Client did not send a token\");\n      }\n      byte[] saslToken = saslMessage.getToken().toByteArray();\n      LOG.debug(\"Have read input token of size {} for processing by saslServer.evaluateResponse()\",\n          saslToken.length);\n      saslToken = saslServer.evaluateResponse(saslToken);\n      return buildSaslResponse(\n          saslServer.isComplete() ? SaslState.SUCCESS : SaslState.CHALLENGE,\n          saslToken);\n    }\n","sourceCodeStart":2431,"sourceCodeEnd":2467,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java#L2431-L2467","documentation":"Thrown by the Hadoop IPC server while reading a SASL message from the client. The RpcSaslProto message carries a SaslState that must be NEGOTIATE (client initiating) or RESPONSE (client answering a server challenge); any other state (e.g. SUCCESS, which only the server may send) falls into the default branch and fails the handshake. The server drives the SASL state machine, so an unexpected state is treated as a protocol violation and the connection is torn down.","triggerScenarios":"A client sends RpcSaslProto with state=SUCCESS or an unknown/invalid enum value during NEGOTIATE/RESPONSE processing; a custom or non-Hadoop client hand-crafting SASL protobuf frames; severe client/server Hadoop version skew where the SASL state machine sequencing differs.","commonSituations":"Monitoring agents, load balancers, or port probes speaking garbage into the RPC port that happens to decode to a bad SaslState; homegrown RPC clients built from stale protobuf definitions; mixed-version clusters during rolling upgrades where an old client negotiates SASL against a new server.","solutions":["Align the client's Hadoop version with the server's (same major/minor line) so SASL state sequencing matches","If running a custom client, send SaslState.NEGOTIATE first and only ever reply with SaslState.RESPONSE; never send SUCCESS as a client","Point health checks, TCP probes, and load-balancer checks at the HTTP/JMX port instead of the RPC port","Check the server log for the printed state value and compare it against RpcSaslProto.SaslState in the client's hadoop-common jar to find the version skew"],"exampleFix":"// before (custom client): client declares success itself\nRpcSaslProto.newBuilder().setState(SaslState.SUCCESS).build();\n\n// after: only NEGOTIATE to start, RESPONSE to answer challenges\nRpcSaslProto msg = RpcSaslProto.newBuilder()\n    .setState(firstMessage ? SaslState.NEGOTIATE : SaslState.RESPONSE)\n    .setToken(ByteString.copyFrom(saslToken))\n    .build();","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  proxy = RPC.getProxy(protocol, versionID, addr, conf);\n} catch (IOException e) {\n  Throwable cause = e.getCause() != null ? e.getCause() : e;\n  if (cause instanceof SaslException\n      && cause.getMessage().contains(\"unsupported state\")) {\n    // client/server SASL dialect mismatch: align versions, do not blindly retry\n    throw new ServiceVersionMismatchException(\"SASL state mismatch\", cause);\n  }\n  throw e;\n}","preventionTips":["Pin client and server to the same Hadoop release line in deployment manifests","Never hand-craft RpcSaslProto frames; use the standard RPC client","Keep health checks off the RPC port"],"tags":["sasl","authentication","rpc","protocol-mismatch","hadoop-ipc"],"backgroundTag":"sasl-negotiation-failed","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}