{"record":{"id":"0653730a50bd024d","repo":"apache/cassandra","slug":"cannot-change-transactional-mode-from-s-to-s-for","errorCode":null,"errorMessage":"Cannot change transactional mode from %s to %s for %s.%s before transactional migration has completed","messagePattern":"Cannot change transactional mode from (.+?) to (.+?) for (.+?)\\.(.+?) before transactional migration has completed","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/statements/schema/AlterTableStatement.java","lineNumber":672,"sourceCode":"\n            if (modeChange && next.transactionalMode.accordIsEnabled && !DatabaseDescriptor.getAccordTransactionsEnabled())\n                throw ire(format(\"Cannot change transactional mode to %s for %s.%s with accord.enabled set to false\",\n                                 next.transactionalMode, keyspaceName, tableName));\n\n            // user is manually updating migration mode, don't interfere\n            if (forceMigrationChange)\n            {\n                logger.warn(\"Forcing unsafe migration change from {} to {} with transaction mode {}\", prev.transactionalMigrationFrom, next.transactionalMigrationFrom, next.transactionalMode);\n                return next;\n            }\n\n            if (!modeChange)\n                return next;\n\n            // if the user is trying to revert to the mode being migrated from, allow it. The migration states will be inverted when\n            // the transformation is applied. Otherwise throw\n            if (wasMigrating && next.transactionalMode != prev.transactionalMigrationFrom.from)\n                throw ire(format(\"Cannot change transactional mode from %s to %s for %s.%s before transactional migration has completed\",\n                                 prev.transactionalMode, next.transactionalMode,\n                                 keyspaceName, tableName));\n\n            return next.unbuild().transactionalMigrationFrom(newMigrateFrom).build();\n        }\n\n        @Override\n        public boolean compatibleWith(ClusterMetadata metadata)\n        {\n            return metadata.directory.commonSerializationVersion.isAtLeast(Version.V0);\n        }\n\n        public KeyspaceMetadata apply(Epoch epoch, KeyspaceMetadata keyspace, TableMetadata table, ClusterMetadata metadata)\n        {\n            attrs.validate();\n\n            TableParams params = attrs.asAlteredTableParams(table.params);\n","sourceCodeStart":654,"sourceCodeEnd":690,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/statements/schema/AlterTableStatement.java#L654-L690","documentation":"Once a table is mid-transactional-migration, the only legal mode change is reverting to the mode the table is migrating FROM. validateAndUpdateTransactionalMigration (AlterTableStatement.java:672) throws this InvalidRequest when wasMigrating is true and the requested next.transactionalMode is anything other than prev.transactionalMigrationFrom.from, protecting the invariants of the migration state machine.","triggerScenarios":"While a table is migrating (e.g. off -> accord in progress), issuing ALTER TABLE WITH transactional_mode = X where X is neither the current target mode's continuation nor the original source mode (prev.transactionalMigrationFrom.from).","commonSituations":"Interrupting an in-progress Accord migration with an unrelated mode; scripting repeated mode toggles that land the table in an intermediate migration state; operator trying to 'jump' from migrating directly to a third mode.","solutions":["Revert to the original mode: set transactional_mode back to the value of transactional_migration_from to cancel the migration","Wait for the migration to complete before changing the mode again","Inspect the table's transactional_migration_from in system_schema.tables to know which revert target is legal","Force an unsafe change deliberately via transactional_migration_from override only if you understand the consequences"],"exampleFix":"// table is migrating off -> accord; jumping to another mode fails\n// before\nALTER TABLE orders WITH transactional_mode = 'unsafe_full';\n// after: revert to source mode first\nALTER TABLE orders WITH transactional_mode = 'off';","handlingStrategy":"validation","validationCode":"Row r = session.execute(\"SELECT transactional_mode, transactional_migration_from FROM system_schema.tables WHERE keyspace_name=? AND table_name=?\", ks, table).one(); boolean migrating = r != null && r.getString(\"transactional_migration_from\") != null; // if migrating, only allow reverting to the migration-from mode","typeGuard":null,"tryCatchPattern":"try { session.execute(alterStmt); } catch (InvalidRequestException e) { if (e.getMessage().contains(\"before transactional migration has completed\")) { /* revert to source mode or wait for completion */ } else throw e; }","preventionTips":["Serialize transactional-mode changes; never run overlapping mode ALTERs","Query the table's migration state before altering the mode","Only change modes in one direction and wait for completion between steps"],"tags":["cassandra","accord","migration","state-machine","transactional-mode"],"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"}