{"record":{"id":"a29f248fdf840543","repo":"apache/cassandra","slug":"can-t-apply-a-clustermetadata-from-gossip-with-epo","errorCode":null,"errorMessage":"Can't apply a ClusterMetadata from gossip with epoch ","messagePattern":"Can't apply a ClusterMetadata from gossip with epoch ","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/tcm/ClusterMetadataService.java","lineNumber":539,"sourceCode":"            return;\n        }\n\n        try\n        {\n            reconfigureCMS(ReplicationParams.meta(metadata));\n        }\n        catch (Throwable t)\n        {\n            JVMStabilityInspector.inspectThrowable(t);\n            logger.warn(\"Could not reconfigure CMS, operator should run `nodetool cms reconfigure` to make sure CMS placement is correct\", t);\n        }\n    }\n\n    public boolean applyFromGossip(ClusterMetadata expected, ClusterMetadata updated)\n    {\n        logger.debug(\"Applying from gossip, current={} new={}\", expected, updated);\n        if (!expected.epoch.isBefore(Epoch.EMPTY))\n            throw new IllegalStateException(\"Can't apply a ClusterMetadata from gossip with epoch \" + expected.epoch);\n        if (state() != GOSSIP)\n            throw new IllegalStateException(\"Can't apply a ClusterMetadata from gossip when CMSState is not GOSSIP: \" + state());\n\n        return log.unsafeSetCommittedFromGossip(expected, updated);\n    }\n\n    public void setFromGossip(ClusterMetadata fromGossip)\n    {\n        logger.debug(\"Setting from gossip, new={}\", fromGossip);\n        if (state() != GOSSIP)\n            throw new IllegalStateException(\"Can't apply a ClusterMetadata from gossip when CMSState is not GOSSIP: \" + state());\n        log.unsafeSetCommittedFromGossip(fromGossip);\n    }\n\n    public void forceSnapshot(ClusterMetadata snapshot)\n    {\n        commit(new ForceSnapshot(snapshot));\n    }","sourceCodeStart":521,"sourceCodeEnd":557,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/tcm/ClusterMetadataService.java#L521-L557","documentation":"applyFromGossip is only valid during the gossip migration window, when the expected ClusterMetadata still has an EMPTY (pre-first) epoch. If the expected metadata's epoch is not before Epoch.EMPTY, the metadata is already committed via TCM and applying a gossip-supplied snapshot would regress state, so it throws IllegalStateException with the offending epoch.","triggerScenarios":"Calling applyFromGossip(expected, updated) where expected.epoch is not isBefore(Epoch.EMPTY) — i.e. the node already has a real TCM-committed epoch, yet a gossip-derived metadata update is attempted (e.g. during or after migration).","commonSituations":"A node received gossip metadata after it already transitioned to TCM; mixed-mode cluster where some peers still push gossip state; a bug in migration handoff ordering that delivers a stale gossip update post-commit.","solutions":["Stop applying gossip metadata once the node holds a real TCM epoch; check the epoch guard before calling applyFromGossip.","Verify the migration ordering: applyFromGossip must run only while expected epoch is EMPTY.","If gossip is still propagating stale metadata, complete the upgrade so all peers stop publishing gossip metadata.","Restart the migration path cleanly; do not mix gossip application with post-epoch TCM state."],"exampleFix":"// before\nservice.applyFromGossip(expected, updated); // expected.epoch already > EMPTY\n// after\nif (expected.epoch.isBefore(Epoch.EMPTY))\n    service.applyFromGossip(expected, updated);\nelse\n    logger.warn(\"Skipping gossip apply; epoch already committed: {}\", expected.epoch);","handlingStrategy":"validation","validationCode":"if (!expected.epoch.isBefore(Epoch.EMPTY)) skipGossipApply(expected.epoch);","typeGuard":null,"tryCatchPattern":"try { service.applyFromGossip(expected, updated); } catch (IllegalStateException e) { logger.warn(\"Gossip apply rejected: {}\", e.getMessage()); }","preventionTips":["Gate gossip application on epoch being EMPTY","Stop gossip metadata flow as soon as TCM epochs exist","Complete migration quickly to avoid mixed-mode races"],"tags":["cluster-metadata","epoch","gossip-migration","precondition"],"backgroundTag":"invalid-state-transition","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"}