apache/cassandra · warning

Cluster metadata identifier mismatch from

Error message

Cluster metadata identifier mismatch from {} {}!={}

What it means

A logger.warn (not an exception): in accrual-enabled clusters the gossip SYN carries a cluster metadata identifier; doVerb drops the message when the sender's metadataId is neither EMPTY_METADATA_IDENTIFIER nor equal to the local ClusterMetadata.current().metadataIdentifier. This guards against gossiping with nodes that hold a different cluster metadata epoch/lineage (TCM-era split-brain protection).

Solutions

  1. Verify cluster identity on both sides (`nodetool describecluster` shows cluster metadata id); if the peer belongs to another cluster, remove it from the network.
  2. For a cloned/reset node, wipe its data and commitlog dirs and re-bootstrap so it syncs with the current cluster metadata log.
  3. Ensure the metadata log (replay positions/seed nodes) is intact; if cluster metadata diverged, follow the documented recovery procedure for TCM.
  4. Prevent recurrences by provisioning nodes from images that never contain another cluster's metadata state.

Example fix

// before: node cloned from a template containing old cluster metadata
// after: clean data dirs, then start so it joins current metadata
rm -rf /var/lib/cassandra/data/* /var/lib/cassandra/commitlog/*
service cassandra start  // node syncs ClusterMetadata from the log
Defensive patterns

Strategy: validation

Validate before calling

// never provision nodes from images containing another cluster's metadata state
// compare metadata ids across nodes:
nodetool describecluster  # all nodes should report the same cluster metadata id

Prevention

When it happens

Trigger: A node whose ClusterMetadata identifier diverges from the local node (e.g., a node that was reset/reseeded from a different metadata log, or from a cloned/split cluster) sends a gossip SYN. Nodes with EMPTY_METADATA_IDENTIFIER are still accepted so fresh joins can gossip.

Common situations: Cloning VMs/disks to provision nodes so multiple nodes claim the same or divergent metadata lineage; restoring a node from a backup taken at a different metadata epoch; network partition resolving with a diverged metadata state; mixing nodes from accidentally split clusters.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/gms/GossipDigestSynVerbHandler.java:70

        GossipDigestSyn gDigestMessage = message.payload;
        /* If the message is from a different cluster throw it away. */
        if (!gDigestMessage.clusterId.equals(DatabaseDescriptor.getClusterName()))
        {
            logger.warn("ClusterName mismatch from {} {}!={}", from, gDigestMessage.clusterId, DatabaseDescriptor.getClusterName());
            return;
        }

        if (gDigestMessage.partioner != null && !gDigestMessage.partioner.equals(DatabaseDescriptor.getPartitionerName()))
        {
            logger.warn("Partitioner mismatch from {} {}!={}", from, gDigestMessage.partioner, DatabaseDescriptor.getPartitionerName());
            return;
        }

        if (gDigestMessage.metadataId != ClusterMetadata.EMPTY_METADATA_IDENTIFIER
            && gDigestMessage.metadataId != ClusterMetadata.current().metadataIdentifier)
        {
            logger.warn("Cluster metadata identifier mismatch from {} {}!={}", from, gDigestMessage.metadataId, ClusterMetadata.current().metadataIdentifier);
            return;
        }

        List<GossipDigest> gDigestList = gDigestMessage.getGossipDigests();
        // if the syn comes from a peer performing a shadow round and this node is
        // also currently in a shadow round, send back a minimal ack. This node must
        // be in the sender's seed list and doing this allows the sender to
        // differentiate between seeds from which it is partitioned and those which
        // are in their shadow round
        if (!Gossiper.instance.isEnabled() && NewGossiper.instance.isInShadowRound())
        {
            // a genuine syn (as opposed to one from a node currently
            // doing a shadow round) will always contain > 0 digests
            if (gDigestList.size() > 0)
            {
                logger.debug("Ignoring non-empty GossipDigestSynMessage because currently in gossip shadow round");
                return;
            }

View on GitHub (pinned to 88fd0f6a0e)