apache/cassandra · error · IllegalArgumentException
Only transition from FORBIDDEN to PERMITTED is allowed.
Error message
Only transition from FORBIDDEN to PERMITTED is allowed.
What it means
The other half of the CDC state machine: a segment in FORBIDDEN state (CDC disk quota exceeded, writes blocked) may only transition back to PERMITTED. Any other target state throws IllegalArgumentException, preventing direct jumps like FORBIDDEN->CONTAINS that would bypass the permit cycle.
Solutions
- Always restore a FORBIDDEN segment through PERMITTED before any other transition.
- Let CommitLog's own setCDCBlockWrites/quota machinery drive FORBIDDEN/PERMITTED changes instead of manual calls.
- Inspect current state with getCDCState() and implement a transition map honoring FORBIDDEN->PERMITTED only.
- Check cdc_free_space_in_mb sizing so quota logic (not state misuse) resolves the block.
Example fix
// before segment.setCDCState(CDCState.CONTAINS); // segment FORBIDDEN // after segment.setCDCState(CDCState.PERMITTED); // required hop segment.setCDCState(CDCState.CONTAINS);
Defensive patterns
Strategy: validation
Validate before calling
if (segment.getCDCState() == CDCState.FORBIDDEN && newState != CDCState.PERMITTED)
throw new IllegalArgumentException("FORBIDDEN may only transition to PERMITTED"); Try / catch
try {
segment.setCDCState(newState);
} catch (IllegalArgumentException e) {
logger.warn("Blocked CDC transition (FORBIDDEN requires PERMITTED): {}", e.getMessage());
} Prevention
- Route FORBIDDEN recovery exclusively through PERMITTED
- Use CommitLog.setCDCBlockWrites rather than direct state writes
- Size cdc_free_space_in_mb so quota unblocking occurs normally
When it happens
Trigger: Calling setCDCState(FORBIDDEN->CONTAINS) or FORBIDDEN->FORBIDDEN is fine but e.g. setCDCState with newState != PERMITTED while cdcState == FORBIDDEN, typically from custom CDC quota logic or tests.
Common situations: Custom cdc_free_space_in_mb handling code forcing states; tests simulating quota blocking and forgetting to return via PERMITTED; races where allocation attempts to mark CONTAINS on a blocked segment.
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.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Cannot transition from CONTAINS to any other state.
- 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/32a7985257cc917b.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java:697
* 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;
private final ByteBuffer buffer;
Allocation(CommitLogSegment segment, OpOrder.Group appendOp, int position, ByteBuffer buffer)View on GitHub (pinned to 88fd0f6a0e)