apache/cassandra · error · RuntimeException
Transfer of stream %s already completed or aborted (perhaps
Error message
Transfer of stream %s already completed or aborted (perhaps session failed?).
What it means
OutgoingStreamMessage tracks per-stream lifecycle state (transferring/completed/aborted) with synchronized methods. startTransfer throws RuntimeException if the stream is already marked completed, meaning serialize was invoked on a stream whose transfer had already finished or been aborted — usually because the session failed and retried sending the same stream without resetting its state.
Source
Thrown at src/java/org/apache/cassandra/streaming/messages/OutgoingStreamMessage.java:105
stream.write(session, out, version);
}
@VisibleForTesting
public synchronized void finishTransfer()
{
transferring = false;
//session was aborted mid-transfer, now it's safe to release
if (completed)
{
stream.finish();
}
}
@VisibleForTesting
public synchronized void startTransfer()
{
if (completed)
throw new RuntimeException(String.format("Transfer of stream %s already completed or aborted (perhaps session failed?).",
stream));
transferring = true;
}
public synchronized void complete()
{
if (!completed)
{
completed = true;
//release only if not transferring
if (!transferring)
{
stream.finish();
}
}
}
@OverrideView on GitHub (pinned to 88fd0f6a0e)
Solutions
- Recreate the stream session instead of retrying the same stream objects: re-run the repair/bootstrap operation so fresh OutgoingStream instances are created
- Check logs for the earlier session failure/abort that completed the stream and address that root cause (network, timeouts)
- Upgrade to a version with session retry-state fixes if retries are producing this repeatedly
- Avoid manually invoking transfer/serialize on the same OutgoingStreamMessage concurrently (e.g. in tests/tools)
Example fix
// before: reusing old stream after failure session.send(oldStreamMessage); // after: let the session rebuild streams StreamResult result = streamPlan.execute(); // new session, new streams
Defensive patterns
Strategy: validation
Validate before calling
if (streamMessage.isCompleted()) throw new IllegalStateException("cannot resend completed stream " + streamMessage); Prevention
- Never reuse OutgoingStreamMessage objects across session retries; rebuild streams per attempt
- Avoid invoking transfer/serialize concurrently on the same stream (tests/tools)
- Fix the underlying session failure rather than blind-retrying the same stream
When it happens
Trigger: A StreamSession retries or re-serializes an OutgoingStreamMessage after the stream was completed()/aborted(); concurrent send attempts on the same stream; a failed session whose streams are re-sent by a higher-level retry loop.
Common situations: Streaming retry after a network failure where session state was not fully reset; repair retries racing with stream completion; internal concurrency bugs where complete() and startTransfer() interleave across channels.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Node is still rebuilding. Check nodetool netstats.
- 0x0000
- Bootstrap can be started exactly once, but seems to have alr
- channel's transferring state is currently set to true. refus
- Queue is empty
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/4aba124e88f74679.
Report an issue: GitHub.