apache/hadoop · error · IOException

SASL handshake completed, but channel does not have acceptab

Error message

SASL handshake completed, but channel does not have acceptable quality of protection, requested = %s, negotiated(effective) = %s

What it means

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').

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/protocol/datatransfer/sasl/DataTransferSaslUtil.java:113

   * @throws IOException for any error
   */
  public static void checkSaslComplete(SaslParticipant sasl,
      Map<String, String> saslProps) throws IOException {
    if (!sasl.isComplete()) {
      throw new IOException("Failed to complete SASL handshake");
    }
    Set<String> requestedQop = ImmutableSet.copyOf(Arrays.asList(
        saslProps.get(Sasl.QOP).split(",")));
    String negotiatedQop = sasl.getNegotiatedQop();
    LOG.debug("{}: Verifying QOP: requested = {}, negotiated = {}",
        sasl, requestedQop, negotiatedQop);
    // Treat null negotiated QOP as "auth" for the purpose of verification
    // Code elsewhere does the same implicitly
    if(negotiatedQop == null) {
      negotiatedQop = "auth";
    }
    if (!requestedQop.contains(negotiatedQop)) {
      throw new IOException(String.format("SASL handshake completed, but " +
          "channel does not have acceptable quality of protection, " +
          "requested = %s, negotiated(effective) = %s", requestedQop, negotiatedQop));
    }
  }

  /**
   * Check whether requested SASL Qop contains privacy.
   *
   * @param saslProps properties of SASL negotiation
   * @return boolean true if privacy exists
   */
  public static boolean requestedQopContainsPrivacy(
      Map<String, String> saslProps) {
    Set<String> requestedQop = ImmutableSet.copyOf(Arrays.asList(
        saslProps.get(Sasl.QOP).split(",")));
    return requestedQop.contains("auth-conf");
  }

View on GitHub (pinned to 2add963021)

Solutions

  1. 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
  2. If the weaker level is acceptable, add 'authentication' to the client's requested list instead of requesting only 'privacy'
  3. Verify via config dumps / hdfs dfsadmin that every node actually reloaded the setting

Example fix

<!-- before: client only -->
<property>
  <name>dfs.data.transfer.protection</name>
  <value>privacy</value>
</property>

<!-- after: same value everywhere (NN, all DNs, client), list allows negotiation -->
<property>
  <name>dfs.data.transfer.protection</name>
  <value>authentication,integrity,privacy</value>
</property>
Defensive patterns

Strategy: validation

Validate before calling

String protection = conf.get("dfs.data.transfer.protection", "");
if (protection.isEmpty()) {
  // peer may negotiate auth-only while this side expects integrity/privacy: mismatch risk
  LOG.warn("dfs.data.transfer.protection unset on this side");
}

Try / catch

catch (IOException e) with message containing "quality of protection": treat as cluster security-config drift - stop and fix configs, do not retry.

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/7d158846e8a56227. Report an issue: GitHub.