apache/cassandra · error · IllegalStateException

[Stream # ] Complete message can be only received by the…

Error message

[Stream #%s] Complete message can be only received by the initiator!

What it means

In the bidirectional streaming handshake, the Complete message in the 'follower' role path is invalid: only the session initiator may receive/process Complete on this path (pre-4.0 followers are not expected to stream). Receiving Complete as a follower throws this IllegalStateException.

Solutions

  1. Ensure all nodes are Cassandra 4.0+ or that pre-4.0 nodes are excluded from streaming topology changes (upgrade before repair/rebuild).
  2. Check MessagingService.accept_streaming / messaging version negotiation between the peers.
  3. Re-run the streaming operation after all nodes agree on versions; use a new session/planId.
  4. Inspect the planId in logs to identify the peer sending Complete and its Cassandra version.

Example fix

// before
// legacy node sends Complete to follower session
// after
// block streaming from legacy peers
if (messagingVersion < MessagingService.VERSION_40) {
    throw new IOException("Streaming from pre-4.0 node not supported");
}
Defensive patterns

Strategy: validation

Validate before calling

if (messagingVersion < MessagingService.VERSION_40) { /* disallow streaming with this peer */ }

Try / catch

try { session.receiveComplete(...); } catch (IllegalStateException e) { if (e.getMessage().contains("only received by the initiator")) { logger.warn("Complete from legacy follower peer"); } else { throw e; } }

Prevention

When it happens

Trigger: A follower-side StreamSession processing a Complete message where the isInitiator check fails — i.e. a pre-4.0 (legacy) node sending Complete, or a session whose initiator/follower role is mismatched.

Common situations: Upgrading clusters where legacy (pre-4.0) nodes attempt streaming against 4.0+ nodes; misconfigured seeds causing wrong session roles; messaging-version negotiation mistakes.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/streaming/StreamSession.java:1148

    {
        transfers.get(tableId).complete(sequenceNumber);
    }

    /**
     * Check if session is completed on receiving {@code StreamMessage.Type.COMPLETE} message.
     */
    public synchronized void complete()
    {
        logger.debug("[Stream #{}] handling Complete message, state = {}", planId(), state);

        if (!isFollower) // initiator
        {
            initiatorCompleteOrWait();
        }
        else // follower
        {
            // pre-4.0 nodes should not be connected via streaming, see {@link MessagingService#accept_streaming}
            throw new IllegalStateException(String.format("[Stream #%s] Complete message can be only received by the initiator!", planId()));
        }
    }

    /**
     * Synchronize both {@link #complete()} and {@link #maybeCompleted()} to avoid racing
     */
    private synchronized boolean maybeCompleted()
    {
        if (!(receivers.isEmpty() && transfers.isEmpty()))
            return false;

        // if already executed once, skip it
        if (maybeCompleted)
            return true;

        maybeCompleted = true;
        if (!isFollower) // initiator
        {

View on GitHub (pinned to 88fd0f6a0e)