apache/cassandra · error · ProtocolException

Unexpected request expecting READY, AUTHENTICATE, ERROR or…

Error message

Unexpected %s request expecting READY, AUTHENTICATE, ERROR or SUPPORTED

What it means

During protocol negotiation the client's InitialHandler decoder receives an envelope whose message type is not one of READY, AUTHENTICATE, ERROR or SUPPORTED, and throws a ProtocolException. Only those four response types are legal while the connection is still in the STARTUP/negotiating state; anything else indicates a protocol framing or state bug.

Solutions

  1. Log the received message type to identify what the server actually sent.
  2. Remove any intermediary proxies or test a direct connection to the node.
  3. Pin an explicit protocol version in STARTUP options instead of auto-negotiation.
  4. Ensure the pipeline matches the negotiated version (legacy vs modern) and compression settings match the server.
Defensive patterns

Strategy: validation

Validate before calling

// after each response during handshake
Set<Message.Type> allowed = EnumSet.of(Message.Type.READY, Message.Type.AUTHENTICATE, Message.Type.ERROR, Message.Type.SUPPORTED);
if (!allowed.contains(resp.type)) throw new IllegalStateException("Unexpected handshake response " + resp.type);

Try / catch

try { handshake(); } catch (ProtocolException e) { log.warn("Negotiation failure, retrying direct connection", e); connectDirect(); }

Prevention

When it happens

Trigger: Server replies to OPTIONS/STARTUP with an unexpected message type — e.g. a request frame arrives on the legacy pipeline during handshake, or a proxy/mixed-version node answers out of spec.

Common situations: Connecting through a broken or misbehaving proxy; version negotiation glitches between very old/new protocol versions; corruption from a wrong compression/frame-decoder configuration in the pipeline.

Understand the failure class

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/6af3191f8d34f4a4. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/transport/SimpleClient.java:478

                    if (request.header.version.isGreaterOrEqualTo(ProtocolVersion.V5))
                    {
                        configureModernPipeline(ctx, request, largeMessageThreshold);
                        // consuming the message is done when setting up the pipeline
                    }
                    else
                    {
                        configureLegacyPipeline(ctx);
                        // really just removes self from the pipeline, so pass this message on
                        ctx.pipeline().context(Envelope.Decoder.class).fireChannelRead(request);
                    }
                    break;
                case SUPPORTED:
                case ERROR:
                    // just pass through
                    results.add(request);
                    break;
                default:
                    throw new ProtocolException(String.format("Unexpected %s request expecting " +
                                                              "READY, AUTHENTICATE, ERROR or SUPPORTED",
                                                              request.header.type));
            }
        }

        private void configureModernPipeline(ChannelHandlerContext ctx, Envelope request, int largeMessageThreshold)
        {
            logger.info("Configuring modern pipeline");
            ChannelPipeline pipeline = ctx.pipeline();
            pipeline.remove(HandlerNames.ENVELOPE_DECODER);
            pipeline.remove(HandlerNames.MESSAGE_DECODER);
            pipeline.remove(HandlerNames.MESSAGE_ENCODER);
            pipeline.remove(HandlerNames.RESPONSE_HANDLER);

            BufferPoolAllocator allocator = GlobalBufferPoolAllocator.instance;
            Channel channel = ctx.channel();
            channel.config().setOption(ChannelOption.ALLOCATOR, allocator);
            int queueCapacity = 1 << 20;  // 1MiB

View on GitHub (pinned to 88fd0f6a0e)