apache/cassandra · error · IllegalStateException

Bad CMS state:

Error message

Bad CMS state: 

What it means

The commit processor wrapper switches on the node's CMS state (RESET, LOCAL, REMOTE, GOSSIP) to pick which processor handles commits. If the CMSState enum holds a value not covered by the switch, this internal-invariant IllegalStateException is thrown. It should be unreachable in normal operation and usually indicates a new enum constant added without updating this switch.

Solutions

  1. Report as a bug with the full state string from the message and the Cassandra version
  2. Check for version skew / mixed-version cluster during rolling upgrades and align versions
  3. If running a custom build, update the switch statement to handle the new CMSState value
  4. Restart the node to clear in-memory state and re-verify with a standard build

Example fix

// before
switch (cmsStateSupplier.get())
{
    case RESET:
    case LOCAL:
        return Pair.create(state, local);
    case REMOTE:
        return Pair.create(state, remote);
    case GOSSIP:
        return Pair.create(state, gossip);
}
throw new IllegalStateException("Bad CMS state: " + state);
// after (add the missing case as soon as a new state exists)
switch (cmsStateSupplier.get())
{
    case RESET:
    case LOCAL:
        return Pair.create(state, local);
    case REMOTE:
        return Pair.create(state, remote);
    case GOSSIP:
        return Pair.create(state, gossip);
    case NEW_STATE:
        return Pair.create(state, newStateProcessor);
}
throw new IllegalStateException("Bad CMS state: " + state);
Defensive patterns

Strategy: validation

Validate before calling

CMSState state = ClusterMetadataService.instance.getState();
Set<CMSState> known = EnumSet.of(CMSState.RESET, CMSState.LOCAL, CMSState.REMOTE, CMSState.GOSSIP);
if (!known.contains(state)) throw new IllegalStateException("Unsupported CMS state " + state);

Type guard

boolean isKnownState = (CMSState s) -> s == CMSState.RESET || s == CMSState.LOCAL || s == CMSState.REMOTE || s == CMSState.GOSSIP;

Try / catch

try
{
    commitViaPath(path, entryId, transform, lastKnown, retry);
}
catch (IllegalStateException e)
{
    if (e.getMessage() != null && e.getMessage().startsWith("Bad CMS state:"))
        throw new AssertionError("Internal bug: unhandled CMSState — report with full state", e);
    throw e;
}

Prevention

When it happens

Trigger: Committing a transformation via the CMS-state-dispatching Commit.Path when ClusterMetadataService.state resolves to an unhandled CMSState value — practically only after a code change adds a new CMSState constant or corrupted in-memory state.

Common situations: Running a patched/custom Cassandra build where a new CMS state was added; upgrade skew where different code paths disagree on states; otherwise a genuine internal bug report.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/tcm/ClusterMetadataService.java:1090

        public Processor delegate()
        {
            return delegateInternal().right;
        }

        private Pair<State, Processor> delegateInternal()
        {
            State state = cmsStateSupplier.get();
            switch (state)
            {
                case LOCAL:
                case RESET:
                    return Pair.create(state, local);
                case REMOTE:
                    return Pair.create(state, remote);
                case GOSSIP:
                    return Pair.create(state, gossip);
            }
            throw new IllegalStateException("Bad CMS state: " + state);
        }

        @Override
        public Commit.Result commit(Entry.Id entryId, Transformation transform, Epoch lastKnown, Retry retryPolicy)
        {
            while (true)
            {
                try
                {
                    Pair<State, Processor> delegate = delegateInternal();
                    Commit.Result result = delegate.right.commit(entryId, transform, lastKnown, retryPolicy);
                    ClusterMetadataService.State state = delegate.left;
                    if (state == LOCAL || state == RESET)
                        replicator.send(result, null);
                    return result;
                }
                catch (NotCMSException e)
                {

View on GitHub (pinned to 88fd0f6a0e)