apache/cassandra · error · ProtocolException
Unexpected message , expecting
Error message
Unexpected message %s, expecting %s
What it means
A ProtocolException thrown when a message arrives while the connection is in the AUTHENTICATING stage but is neither AUTH_RESPONSE (SASL, protocol v2+) nor CREDENTIALS (legacy v1 auth). The server expects exactly one authentication message during this stage; anything else breaks the auth handshake and is rejected with an expectation message naming the correct type for the negotiated version.
Solutions
- Configure the client with the correct credentials so it responds with an AUTH_RESPONSE frame
- Match client auth settings to the server's authenticator (cassandra.yaml: authenticator class)
- On protocol v1, send CREDENTIALS instead of SASL_RESPONSE, or better, upgrade to a modern protocol version
- Fix driver state machines that skip the AUTHENTICATE wait step
Example fix
// before
cluster.init(); // no auth provider against PasswordAuthenticator server
// after
Cluster.builder().addContactPoint("127.0.0.1")
.withCredentials("cassandra", "cassandra").build(); Defensive patterns
Strategy: validation
Validate before calling
if (serverRequiresAuth && credentials == null)
throw new IllegalStateException("server authenticates; client must provide credentials to send AUTH_RESPONSE"); Type guard
boolean validAuthMessage(Message.Type t, ProtocolVersion v) { return v == ProtocolVersion.V1 ? t == Message.Type.CREDENTIALS : t == Message.Type.AUTH_RESPONSE; } Try / catch
try { session = cluster.connect(); } catch (AuthenticationException | NoHostAvailableException e) { if (mentionsAuthHandshake(e)) applyCredentialsAndRetry(); else throw e; } Prevention
- Keep client auth config in sync with server authenticator (cassandra.yaml)
- Never connect without credentials when the server uses PasswordAuthenticator
- Don't send queries while the connection is mid-authentication
- Use protocol v2+ (SASL) instead of legacy v1 CREDENTIALS
When it happens
Trigger: During authentication (server sent AUTHENTICATE), client sends QUERY/STARTUP/OPTIONS or a malformed frame instead of AuthResponse (or Credentials on v1); validateNewMessage() rejects it with 'Unexpected message %s, expecting CREDENTIALS/SASL_RESPONSE'.
Common situations: Client without authentication configured connecting to an auth-required cluster, wrong authenticator mismatch between client and server (PasswordAuthenticator vs AllowAllAuthenticator), custom drivers skipping the SASL exchange, or race in connection setup code.
Related errors
- Unexpected message , expecting STARTUP or OPTIONS
- Unexpected message STARTUP, the connection is already…
- Auth check after connection closed
- Authentication error
- Authentication ID must not be null
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/1a9f2b70fb1d0153.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/transport/ServerConnection.java:90
}
ConnectionStage stage()
{
return stage;
}
QueryState validateNewMessage(Message.Type type, ProtocolVersion version)
{
switch (stage)
{
case ESTABLISHED:
if (type != Message.Type.STARTUP && type != Message.Type.OPTIONS)
throw new ProtocolException(String.format("Unexpected message %s, expecting STARTUP or OPTIONS", type));
break;
case AUTHENTICATING:
// Support both SASL auth from protocol v2 and the older style Credentials auth from v1
if (type != Message.Type.AUTH_RESPONSE && type != Message.Type.CREDENTIALS)
throw new ProtocolException(String.format("Unexpected message %s, expecting %s", type, version == ProtocolVersion.V1 ? "CREDENTIALS" : "SASL_RESPONSE"));
break;
case READY:
if (type == Message.Type.STARTUP)
throw new ProtocolException("Unexpected message STARTUP, the connection is already initialized");
break;
default:
throw new AssertionError();
}
return new QueryState(clientState);
}
void applyStateTransition(Message.Type requestType, Message.Type responseType)
{
switch (stage)
{
case ESTABLISHED:
if (requestType == Message.Type.STARTUP)View on GitHub (pinned to 88fd0f6a0e)