{"record":{"id":"4268a31deaca7b6e","repo":"apache/cassandra","slug":"can-not-commit-transformation-s-s","errorCode":null,"errorMessage":"Can not commit transformation: \"%s\"(%s).","messagePattern":"Can not commit transformation: \"(.+?)\"\\((.+?)\\)\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/tcm/ClusterMetadataService.java","lineNumber":637,"sourceCode":"\n    public final Supplier<Entry.Id> entryIdGen = new Entry.DefaultEntryIdGen();\n\n    public interface CommitSuccessHandler<T>\n    {\n        T accept(ClusterMetadata latest);\n    }\n\n    public interface CommitFailureHandler<T>\n    {\n        T accept(ExceptionCode code, String message);\n    }\n\n    public ClusterMetadata commit(Transformation transform)\n    {\n        return commit(transform,\n                      metadata -> metadata,\n                      (code, message) -> {\n                          throw new IllegalStateException(String.format(\"Can not commit transformation: \\\"%s\\\"(%s).\",\n                                                                        code, message));\n                      });\n    }\n\n    /**\n     * Attempt to commit the transformation (with retries).\n     * <p>\n     * Since we can not rely on reliability of the network or even the fact that the committing node will stay alive\n     * for the duration of commit, we have to allow for subsequent discovery of the transformation effects, which can\n     * be made visible either by replaying the log, or receiving the metadata snapshot.\n     * <p>\n     * In other words, there is no reliable way to find out whether _this particular_ transformation has been executed\n     * while we are allowing replay from snapshot, since even failure response from the CMS does not guarantee\n     * Paxos re-proposal, which would place the transformation into the log during proposal _by some other_ CMS node.\n     * <p>\n     * Protocol does foresee the concept of EntryId that would allow discovery of the committed transformations\n     * without changes to binary protocol, but this change was left out from the initial implementation of TCM.\n     * <p>","sourceCodeStart":619,"sourceCodeEnd":655,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/tcm/ClusterMetadataService.java#L619-L655","documentation":"This is the default failure path of ClusterMetadataService.commit(Transformation): when the commit is rejected, the supplied CommitFailureHandler wraps the rejection code and message in an IllegalStateException. It means the transformation (schema change, topology change, node operation) was not accepted by the metadata log and no callers were registered to handle the failure.","triggerScenarios":"Calling ClusterMetadataService.commit(transformation) (or forceSnapshot) where the transformation fails to commit — e.g. rejected by precondition checks, election lost, conflicting concurrent transformation, or replication/validation failure — with no custom onFailure handler.","commonSituations":"Concurrent conflicting topology changes (two nodes altering RF or joining simultaneously), schema changes rejected due to invalid replication settings, committing transformations on a node that is not the CMS leader or lost leadership mid-commit, bootstrap/decommission races.","solutions":["Read the embedded rejection code and message in the exception to identify why the transformation was rejected.","Retry the commit after resolving the conflicting state (e.g. wait for the competing transformation to settle).","Provide a custom CommitFailureHandler to commit() to handle known rejection codes instead of relying on the throwing default.","Verify the node is the current CMS leader / can reach the CMS before committing transformations.","Validate transformation preconditions (e.g. replication params, node states) before calling commit."],"exampleFix":"// before\nmetadataService.commit(new AddToCMS(...)); // throws raw IllegalStateException on rejection\n// after\nmetadataService.commit(transform,\n    md -> md,\n    (code, message) -> {\n        logger.warn(\"Commit rejected: {} - {}\", code, message);\n        return RetryResult.retryLater();\n    });","handlingStrategy":"try-catch","validationCode":"// Validate preconditions before commit\nassert ClusterMetadata.current().schema.getReplicationInfo() != null;","typeGuard":null,"tryCatchPattern":"try { service.commit(transform); }\ncatch (IllegalStateException e) { logger.error(\"Transformation rejected: {}\", e.getMessage()); /* inspect code/message embedded */ }","preventionTips":["Pass a custom CommitFailureHandler for expected rejections","Avoid concurrent conflicting topology transformations","Check CMS leadership before committing","Validate replication/parameter preconditions up front"],"tags":["commit","transformation","cluster-metadata","rejection"],"backgroundTag":"internal-invariant-violation","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}