apache/cassandra · warning · IllegalStateException

%s is not currently joining the CMS

Error message

%s is not currently joining the CMS

What it means

CMSMembership.cancelJoining removes a node from the joiningMembers set. It throws IllegalStateException if the id is not currently in that set, because there is no in-flight join to cancel — the transformation would be a no-op or hide a state bug.

Source

Thrown at src/java/org/apache/cassandra/tcm/CMSMembership.java:150

    public Set<NodeId> fullMembers()
    {
        return fullMembers;
    }

    public CMSMembership startJoining(NodeId id)
    {
        if (joiningMembers.contains(id))
            throw new IllegalStateException(id + " is already joining the CMS");
        if (fullMembers.contains(id))
            throw new IllegalStateException(id + " has already fully joined the CMS");

        return new CMSMembership(lastModified, fullMembers, joiningMembers.with(id));
    }

    public CMSMembership cancelJoining(NodeId id)
    {
        if (!joiningMembers.contains(id))
            throw new IllegalStateException(id + " is not currently joining the CMS");
        if (fullMembers.contains(id))
            throw new IllegalStateException(id + " has already fully joined the CMS");

        return new CMSMembership(lastModified, fullMembers, joiningMembers.without(id));
    }

    public CMSMembership finishJoining(NodeId id)
    {
        if (!joiningMembers.contains(id))
            throw new IllegalStateException(id + " is not currently joining the CMS");
        if (fullMembers.contains(id))
            throw new IllegalStateException(id + " has already fully joined the CMS");

        return new CMSMembership(lastModified, fullMembers.with(id), joiningMembers.without(id));
    }

    public CMSMembership leave(NodeId id)
    {

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Before cancelling, read the node's current CMS state from the latest epoch and only cancel if it is genuinely in joiningMembers
  2. Handle the exception as an expected race in join timeout logic: re-read metadata and decide based on current state (finished joining? then nothing to do)
  3. Serialize join lifecycle operations through a single owner so cancel cannot race finishJoining
  4. If the join state is stuck inconsistent, fix it via explicit finishJoining or a fresh startJoining rather than cancelJoining

Example fix

// before
membership = cms.cancelJoining(nodeId); // throws if not joining
// after
if (cms.joiningMembers().contains(nodeId))
    membership = cms.cancelJoining(nodeId);
Defensive patterns

Strategy: validation

Validate before calling

if (!membership.joiningMembers().contains(nodeId)) return; // nothing to cancel

Prevention

When it happens

Trigger: Applying a cancelJoining transformation for a NodeId absent from joiningMembers — cancelling a join that already finished (or failed) via finishJoining, was never started, or whose state was already rolled forward/back in a later epoch.

Common situations: Timeout handling that cancels a join after it already completed; running cleanup for joins on wrong/stale epoch snapshots; double-cancellation from two failure handlers.

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


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