{"record":{"id":"7d158846e8a56227","repo":"apache/hadoop","slug":"sasl-handshake-completed-but-channel-does-not-hav","errorCode":null,"errorMessage":"SASL handshake completed, but channel does not have acceptable quality of protection, requested = %s, negotiated(effective) = %s","messagePattern":"SASL handshake completed, but channel does not have acceptable quality of protection, requested = (.+?), negotiated\\(effective\\) = (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/protocol/datatransfer/sasl/DataTransferSaslUtil.java","lineNumber":113,"sourceCode":"   * @throws IOException for any error\n   */\n  public static void checkSaslComplete(SaslParticipant sasl,\n      Map<String, String> saslProps) throws IOException {\n    if (!sasl.isComplete()) {\n      throw new IOException(\"Failed to complete SASL handshake\");\n    }\n    Set<String> requestedQop = ImmutableSet.copyOf(Arrays.asList(\n        saslProps.get(Sasl.QOP).split(\",\")));\n    String negotiatedQop = sasl.getNegotiatedQop();\n    LOG.debug(\"{}: Verifying QOP: requested = {}, negotiated = {}\",\n        sasl, requestedQop, negotiatedQop);\n    // Treat null negotiated QOP as \"auth\" for the purpose of verification\n    // Code elsewhere does the same implicitly\n    if(negotiatedQop == null) {\n      negotiatedQop = \"auth\";\n    }\n    if (!requestedQop.contains(negotiatedQop)) {\n      throw new IOException(String.format(\"SASL handshake completed, but \" +\n          \"channel does not have acceptable quality of protection, \" +\n          \"requested = %s, negotiated(effective) = %s\", requestedQop, negotiatedQop));\n    }\n  }\n\n  /**\n   * Check whether requested SASL Qop contains privacy.\n   *\n   * @param saslProps properties of SASL negotiation\n   * @return boolean true if privacy exists\n   */\n  public static boolean requestedQopContainsPrivacy(\n      Map<String, String> saslProps) {\n    Set<String> requestedQop = ImmutableSet.copyOf(Arrays.asList(\n        saslProps.get(Sasl.QOP).split(\",\")));\n    return requestedQop.contains(\"auth-conf\");\n  }\n","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/protocol/datatransfer/sasl/DataTransferSaslUtil.java#L95-L131","documentation":"The SASL handshake completed, but the negotiated quality of protection (e.g. 'auth' = authentication only) is not among the levels requested via dfs.data.transfer.protection (e.g. 'privacy'). HDFS refuses to silently downgrade data-transfer security, so checkSaslComplete() throws once requestedQop.contains(negotiatedQop) fails (null negotiated QOP is treated as 'auth').","triggerScenarios":"Client (or DataNode) requests dfs.data.transfer.protection=privacy while the peer only offers or defaults to authentication; or one side lists 'integrity' and the other negotiates 'auth'. The comparison in checkSaslComplete() splits the Sasl.QOP property into the requested set and matches the negotiated value against it.","commonSituations":"Security config applied to only part of the cluster (hardened client, unconfigured DataNodes); hand-edited core-site.xml/hdfs-site.xml diverging between nodes; connecting a secured application to a cluster without data transfer protection.","solutions":["Set dfs.data.transfer.protection to the same ordered list (e.g. authentication,integrity,privacy) in NameNode, all DataNodes and client configs, then restart the services","If the weaker level is acceptable, add 'authentication' to the client's requested list instead of requesting only 'privacy'","Verify via config dumps / hdfs dfsadmin that every node actually reloaded the setting"],"exampleFix":"<!-- before: client only -->\n<property>\n  <name>dfs.data.transfer.protection</name>\n  <value>privacy</value>\n</property>\n\n<!-- after: same value everywhere (NN, all DNs, client), list allows negotiation -->\n<property>\n  <name>dfs.data.transfer.protection</name>\n  <value>authentication,integrity,privacy</value>\n</property>","handlingStrategy":"validation","validationCode":"String protection = conf.get(\"dfs.data.transfer.protection\", \"\");\nif (protection.isEmpty()) {\n  // peer may negotiate auth-only while this side expects integrity/privacy: mismatch risk\n  LOG.warn(\"dfs.data.transfer.protection unset on this side\");\n}","typeGuard":null,"tryCatchPattern":"catch (IOException e) with message containing \"quality of protection\": treat as cluster security-config drift - stop and fix configs, do not retry.","preventionTips":["Template one dfs.data.transfer.protection value across NN, DNs and all clients","List multiple levels (authentication,integrity,privacy) when flexible downgrade is acceptable","Restart and verify configs on every node after security changes"],"tags":["hdfs","sasl","qop","security","configuration"],"backgroundTag":"sasl-qop-mismatch","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}