apache/cassandra · warning · IllegalStateException

has already fully joined the CMS

Error message

 has already fully joined the CMS

What it means

Within CMSMembership.cancelJoining, after confirming the node is in joiningMembers, it also checks fullMembers; if the node has already fully joined, IllegalStateException with 'has already fully joined the CMS' is thrown — cancelling is invalid because the join already completed.

Source

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

        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)
    {
        if (joiningMembers.contains(id))
            throw new IllegalStateException(id + " is currently joining the CMS, ");

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Re-read the latest metadata and check fullMembers before issuing cancelJoining; treat an already-full member as joined (success)
  2. Restructure timeout handlers to always re-fetch current CMS state instead of acting on captured snapshots
  3. Coordinate join lifecycle (start/cancel/finish) through one serialized owner to remove the race
  4. If the node joined successfully, no action is needed — update automation state and stop the cancel path

Example fix

// before
membership = cms.cancelJoining(nodeId);
// after
if (cms.fullMembers().contains(nodeId)) return; // join completed; nothing to cancel
if (cms.joiningMembers().contains(nodeId))
    membership = cms.cancelJoining(nodeId);
Defensive patterns

Strategy: validation

Validate before calling

if (membership.fullMembers().contains(nodeId)) return; // join already completed; do not cancel

Prevention

When it happens

Trigger: A cancelJoining transformation racing with finishJoining: the cancel was validated against a stale snapshot in which the node was joining, but by the time it applies, the node already appears in fullMembers; or a timeout handler cancelling a join that completed successfully.

Common situations: Join timeout fires just as the join finishes; two failure handlers acting on the same join; orchestration reading an outdated epoch snapshot before issuing the cancel.

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/3960788bd5b03c04. Report an issue: GitHub.