apache/kafka · error · SchemaException

The response is unrelated to Sasl request since its correlat

Error message

The response is unrelated to Sasl request since its correlation id is {responseCorrelationId} and the reserved range for Sasl request is [ {minReservedCorrelationId},{maxReservedCorrelationId}]

What it means

Thrown as a SchemaException by NetworkClient.parseResponse when a CorrelationIdMismatchException is caught, the original request header's correlation id is inside the SASL reserved range, and the response's correlation id is NOT inside that reserved range. It signals that the bytes received during the SASL handshake do not belong to the SASL exchange at all, so the client refuses to feed them to the authenticator. The reserved range bounds are included so the mismatch is unambiguous.

Source

Thrown at clients/src/main/java/org/apache/kafka/clients/NetworkClient.java:925

     */
    private LeastLoadedNode handleEmptyNodeList() {
        if (bootstrapConfiguration == BootstrapConfiguration.DISABLED || metadataUpdater.isBootstrapped()) {
            throw new IllegalStateException("There are no nodes in the Kafka cluster");
        }

        log.debug("No nodes available yet, still in bootstrap phase");
        return new LeastLoadedNode(null, false);
    }

    public static AbstractResponse parseResponse(ByteBuffer responseBuffer, RequestHeader requestHeader) {
        try {
            return AbstractResponse.parseResponse(responseBuffer, requestHeader);
        } catch (BufferUnderflowException e) {
            throw new SchemaException("Buffer underflow while parsing response for request with header " + requestHeader, e);
        } catch (CorrelationIdMismatchException e) {
            if (SaslClientAuthenticator.isReserved(requestHeader.correlationId())
                && !SaslClientAuthenticator.isReserved(e.responseCorrelationId()))
                throw new SchemaException("The response is unrelated to Sasl request since its correlation id is "
                    + e.responseCorrelationId() + " and the reserved range for Sasl request is [ "
                    + SaslClientAuthenticator.MIN_RESERVED_CORRELATION_ID + ","
                    + SaslClientAuthenticator.MAX_RESERVED_CORRELATION_ID + "]");
            else {
                throw e;
            }
        }
    }

    /**
     * Post process disconnection of a node
     *
     * @param responses The list of responses to update
     * @param nodeId Id of the node to be disconnected
     * @param now The current time
     * @param disconnectState The state of the disconnected channel
     */
    private void processDisconnection(List<ClientResponse> responses,

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Eliminate any proxy/sidecar between the client and broker during the SASL handshake, or ensure it preserves correlation ids verbatim.
  2. Confirm the SASL mechanism configured on the client is supported and identical to the broker (sasl.mechanism).
  3. Verify the JAAS config and credentials are correct so the broker accepts, not rejects, the SASL exchange.
  4. Upgrade broker and client to the latest patch release to pick up correlation-id/framing fixes.
  5. Capture a pcap of the handshake to confirm no third party is injecting frames onto the connection.

Example fix

// before: traffic routed through a rewriting L7 proxy
props.put("bootstrap.servers", "proxy.internal:443");
// after: direct to brokers, proxy bypassed for SASL
props.put("bootstrap.servers", "broker1:9093,broker2:9093");
Defensive patterns

Strategy: retry

Validate before calling

// This error is raised after a malformed SASL response arrives; nothing the caller sends can prevent it.
// Defensive pre-check: only expect SASL responses on connections mid-handshake.
if (!saslHandshakeInProgress(nodeId)) {
    throw new IllegalStateException(
        "Refusing to parse a SASL response for node " + nodeId + " - no handshake in flight");
}

Type guard

// Narrow a response correlation id into the SASL-reserved band before trusting it.
public static boolean isReservedSaslCorrelation(int correlationId) {
    return correlationId >= org.apache.kafka.common.security.authenticator.SaslClientAuthenticator.MIN_RESERVED_CORRELATION_ID
        && correlationId <= org.apache.kafka.common.security.authenticator.SaslClientAuthenticator.MAX_RESERVED_CORRELATION_ID;
}
// If the inbound correlation id is outside the reserved band during a SASL exchange,
// the response is for a different (non-SASL) request — drop it.

Try / catch

try {
    AbstractResponse r = NetworkClient.parseResponse(buf, header);
} catch (org.apache.kafka.common.errors.SchemaException e) {
    if (e.getMessage().startsWith("The response is unrelated to Sasl request")) {
    // The channel interleaved a non-SASL response during handshake, typically after a reconnect.
    // Re-authenticate: close the connection, re-handshake SASL, then retry the original request.
    return reauthenticateAndRetry(node);
    }
    throw e;
}

Prevention

When it happens

Trigger: During SASL authentication, the broker (or an intermediary) sends a response whose correlation id falls outside the range reserved by SaslClientAuthenticator for in-flight SASL requests. This is caught in parseResponse only for requests whose correlation id was reserved; otherwise the raw CorrelationIdMismatchException is rethrown. Typical of a man-in-the-middle injecting traffic, a proxy that rewrites correlation ids, or a broker bug sending the wrong frame at the wrong time.

Common situations: A sidecar/proxy/load-balancer that rewrites or reorders frames between client and broker; SASL mechanism downgrade attacks where injected bytes are presented as the SASL response; broker version with a known framing regression during SASL handshake; rare race when the connection is reused across sessions and correlation id accounting drifts.

Related errors


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/2f35d479d78fb9c2.json. Report an issue: GitHub.