{"record":{"id":"5f7fbbb20d8f4112","repo":"apache/cassandra","slug":"cluster-metadata-identifier-mismatch-from","errorCode":null,"errorMessage":"Cluster metadata identifier mismatch from {} {}!={}","messagePattern":"Cluster metadata identifier mismatch from (.+?) (.+?)!=(.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/java/org/apache/cassandra/gms/GossipDigestSynVerbHandler.java","lineNumber":70,"sourceCode":"\n        GossipDigestSyn gDigestMessage = message.payload;\n        /* If the message is from a different cluster throw it away. */\n        if (!gDigestMessage.clusterId.equals(DatabaseDescriptor.getClusterName()))\n        {\n            logger.warn(\"ClusterName mismatch from {} {}!={}\", from, gDigestMessage.clusterId, DatabaseDescriptor.getClusterName());\n            return;\n        }\n\n        if (gDigestMessage.partioner != null && !gDigestMessage.partioner.equals(DatabaseDescriptor.getPartitionerName()))\n        {\n            logger.warn(\"Partitioner mismatch from {} {}!={}\", from, gDigestMessage.partioner, DatabaseDescriptor.getPartitionerName());\n            return;\n        }\n\n        if (gDigestMessage.metadataId != ClusterMetadata.EMPTY_METADATA_IDENTIFIER\n            && gDigestMessage.metadataId != ClusterMetadata.current().metadataIdentifier)\n        {\n            logger.warn(\"Cluster metadata identifier mismatch from {} {}!={}\", from, gDigestMessage.metadataId, ClusterMetadata.current().metadataIdentifier);\n            return;\n        }\n\n        List<GossipDigest> gDigestList = gDigestMessage.getGossipDigests();\n        // if the syn comes from a peer performing a shadow round and this node is\n        // also currently in a shadow round, send back a minimal ack. This node must\n        // be in the sender's seed list and doing this allows the sender to\n        // differentiate between seeds from which it is partitioned and those which\n        // are in their shadow round\n        if (!Gossiper.instance.isEnabled() && NewGossiper.instance.isInShadowRound())\n        {\n            // a genuine syn (as opposed to one from a node currently\n            // doing a shadow round) will always contain > 0 digests\n            if (gDigestList.size() > 0)\n            {\n                logger.debug(\"Ignoring non-empty GossipDigestSynMessage because currently in gossip shadow round\");\n                return;\n            }","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/gms/GossipDigestSynVerbHandler.java#L52-L88","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify cluster identity on both sides (`nodetool describecluster` shows cluster metadata id); if the peer belongs to another cluster, remove it from the network.","For a cloned/reset node, wipe its data and commitlog dirs and re-bootstrap so it syncs with the current cluster metadata log.","Ensure the metadata log (replay positions/seed nodes) is intact; if cluster metadata diverged, follow the documented recovery procedure for TCM.","Prevent recurrences by provisioning nodes from images that never contain another cluster's metadata state."],"exampleFix":"// before: node cloned from a template containing old cluster metadata\n// after: clean data dirs, then start so it joins current metadata\nrm -rf /var/lib/cassandra/data/* /var/lib/cassandra/commitlog/*\nservice cassandra start  // node syncs ClusterMetadata from the log","handlingStrategy":"validation","validationCode":"// never provision nodes from images containing another cluster's metadata state\n// compare metadata ids across nodes:\nnodetool describecluster  # all nodes should report the same cluster metadata id","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Provision from clean images without prior cluster metadata.","Wipe data/commitlog dirs when re-imaging or cloning nodes.","Monitor `nodetool describecluster` for divergent metadata ids.","Follow the documented TCM recovery procedure if cluster metadata diverges."],"tags":["gossip","cluster-metadata","split-brain"],"backgroundTag":"cluster-metadata-mismatch","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}