apache/cassandra · error · IllegalStateException
unknown stream session
Error message
unknown stream session: %s - %d
What it means
When deserializing an incoming IncomingStreamMessage, the receiver looks up the stream session identified by the header's planId/sessionIndex via StreamManager.instance.findSession. If no session matches, it throws IllegalStateException because streaming data arrived for a session this node does not know about; the incoming bytes cannot be attributed to any live transfer.
Solutions
- Re-initiate streaming from the sender so a new session/planId is negotiated (e.g. re-run repair or nodetool rebuild)
- Check both nodes' logs for the earlier session failure/timeout that removed the session and fix that root cause (timeouts, dropped sessions, GC pauses)
- Ensure cluster clocks and stream_manager settings are consistent; verify no node restart occurred mid-stream
- If streaming persistently fails, run nodetool cleanup/repair after fixing connectivity and retry the operation
Example fix
// after 'unknown stream session' during repair nodetool repair -pr <keyspace> <table> // restart the operation; a fresh session/planId is created
Defensive patterns
Strategy: retry
Try / catch
try { deliverStream(header, input); }
catch (IllegalStateException e) {
if (e.getMessage().startsWith("unknown stream session")) {
logger.warn("stale stream data for {}, asking peer to resend", header.planId);
requestStreamRestart(header.planId);
} else throw e;
} Prevention
- Avoid restarting nodes mid-stream; check nodetool netstats before maintenance
- Keep streaming timeouts generous for large transfers
- After any stream failure, always re-run the operation to create a fresh session rather than pushing more data
- Monitor for session timeouts in logs during repairs/bootstraps
When it happens
Trigger: A peer sends stream data referencing a planId/sessionIndex that was already finished, failed, cancelled, or never registered on this node — e.g. message arrives after the local session timed out or was aborted, or the node restarted mid-stream.
Common situations: Long-running streaming exceeding timeouts so the receiver's session is dropped while sender keeps sending; node restart during streaming; orphaned sender retries after a failed stream session; mismatched cluster state after bootstrap/decommission interruption.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- A node required to move the data consistently is down
- Can not start range streaming as all candidates
- Can't join the ring because bootstrap hasn't completed.
- Cannot deserialize index summary from
- Cannot send stream data messages for preview streaming…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/2bb5e62c0db059c2.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/streaming/messages/IncomingStreamMessage.java:41
import org.apache.cassandra.db.ColumnFamilyStore;
import org.apache.cassandra.io.util.DataInputPlus;
import org.apache.cassandra.streaming.IncomingStream;
import org.apache.cassandra.streaming.StreamManager;
import org.apache.cassandra.streaming.StreamReceiveException;
import org.apache.cassandra.streaming.StreamSession;
import org.apache.cassandra.streaming.StreamingChannel;
import org.apache.cassandra.streaming.StreamingDataOutputPlus;
public class IncomingStreamMessage extends StreamMessage
{
public static Serializer<IncomingStreamMessage> serializer = new Serializer<IncomingStreamMessage>()
{
public IncomingStreamMessage deserialize(DataInputPlus input, int version) throws IOException
{
StreamMessageHeader header = StreamMessageHeader.serializer.deserialize(input, version);
StreamSession session = StreamManager.instance.findSession(header.sender, header.planId, header.sessionIndex, header.sendByFollower);
if (session == null)
throw new IllegalStateException(String.format("unknown stream session: %s - %d", header.planId, header.sessionIndex));
ColumnFamilyStore cfs = ColumnFamilyStore.getIfExists(header.tableId);
if (cfs == null)
throw new StreamReceiveException(session, "CF " + header.tableId + " was dropped during streaming");
try
{
IncomingStream incomingData = cfs.getStreamManager().prepareIncomingStream(session, header);
incomingData.read(input, version);
return new IncomingStreamMessage(incomingData, header);
}
catch (Throwable t)
{
if (t instanceof StreamReceiveException)
throw (StreamReceiveException) t;
// make sure to wrap so the caller always has access to the session to call onError
throw new StreamReceiveException(session, t);
}View on GitHub (pinned to 88fd0f6a0e)