apache/cassandra · error · IllegalArgumentException
Cannot transition from CONTAINS to any other state.
Error message
Cannot transition from CONTAINS to any other state.
What it means
CommitLogSegment.setCDCState enforces CDC state machine rules: once a segment is CONTAINS (holds CDC-indexed data), it may never leave that state — CONTAINS->CONTAINS is idempotent, any other target throws IllegalArgumentException. This guarantees CDC data in a segment is never un-tracked.
Solutions
- Treat CONTAINS as terminal: only call setCDCState(CONTAINS) for such segments.
- Check segment.getCDCState() before requesting a transition.
- If you need a segment without CDC data, create a new segment rather than demoting an existing one.
- Use the race-safe idempotent path: re-requesting CONTAINS on a CONTAINS segment is allowed.
Example fix
// before
segment.setCDCState(CDCState.PERMITTED); // segment already CONTAINS
// after
if (segment.getCDCState() != CDCState.CONTAINS)
segment.setCDCState(CDCState.PERMITTED); Defensive patterns
Strategy: validation
Validate before calling
if (segment.getCDCState() == CDCState.CONTAINS && newState != CDCState.CONTAINS)
throw new IllegalArgumentException("CONTAINS is terminal for CDC state"); Try / catch
try {
segment.setCDCState(newState);
} catch (IllegalArgumentException e) {
logger.warn("Illegal CDC transition on segment {}: {}", segment, e.getMessage());
} Prevention
- Treat CONTAINS as a terminal CDC state
- Read getCDCState() before requesting any transition
- Let CommitLog/CDCSizeTracker drive state changes instead of manual calls
When it happens
Trigger: Calling setCDCState with a state other than CONTAINS while cdcState == CDCState.CONTAINS, e.g. trying to reset a completed segment to PERMITTED/FORBIDDEN, or racing callers that recompute state after the segment became CONTAINS.
Common situations: Custom CDC tooling manipulating segment states; tests simulating CDC transitions; races between CDCSizeTracker.processNewSegment and allocation-time state setting.
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
- Only transition from FORBIDDEN to PERMITTED is allowed.
- Accord journal is configured in periodic mode, while…
- Batch sync specified, but commitlog_sync_period found.
- Can't finish migration, initiator=
- Can't proceed from the state
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/2b9bc356dbce1c6f.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java:694
}
/**
* Change the current cdcState on this CommitLogSegment. There are some restrictions on state transitions and this
* method is idempotent.
*
* @return the old cdc state
*/
public CDCState setCDCState(CDCState newState)
{
if (newState == cdcState)
return cdcState;
// Also synchronized in CDCSizeTracker.processNewSegment and .processDiscardedSegment
synchronized(cdcStateLock)
{
// Need duplicate CONTAINS to be idempotent since 2 threads can race on this lock
if (cdcState == CDCState.CONTAINS && newState != CDCState.CONTAINS)
throw new IllegalArgumentException("Cannot transition from CONTAINS to any other state.");
if (cdcState == CDCState.FORBIDDEN && newState != CDCState.PERMITTED)
throw new IllegalArgumentException("Only transition from FORBIDDEN to PERMITTED is allowed.");
CDCState oldState = cdcState;
cdcState = newState;
return oldState;
}
}
/**
* A simple class for tracking information about the portion of a segment that has been allocated to a log write.
*/
protected static class Allocation
{
private final CommitLogSegment segment;
private final OpOrder.Group appendOp;
private final int position;View on GitHub (pinned to 88fd0f6a0e)