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
- 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
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
- 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
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
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Server asks us to fall back to SIMPLE auth, but this client
- FATAL_INVALID_RPC_HEADER
- ${method} authentication is not enabled. Available:${enable
- Kerberos required for secure registry access
- Cannot create a secured connection if DataNode listens on un
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/7d158846e8a56227.
Report an issue: GitHub.