apache/cassandra · error · InvalidRequestException

Cannot change transactional mode from

Error message

Cannot change transactional mode from %s to %s for %s.%s before transactional migration has completed

What it means

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.

Solutions

  1. Revert to the original mode: set transactional_mode back to the value of transactional_migration_from to cancel the migration
  2. Wait for the migration to complete before changing the mode again
  3. Inspect the table's transactional_migration_from in system_schema.tables to know which revert target is legal
  4. Force an unsafe change deliberately via transactional_migration_from override only if you understand the consequences

Example fix

// table is migrating off -> accord; jumping to another mode fails
// before
ALTER TABLE orders WITH transactional_mode = 'unsafe_full';
// after: revert to source mode first
ALTER TABLE orders WITH transactional_mode = 'off';
Defensive patterns

Strategy: validation

Validate before calling

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

Try / catch

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; }

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/cql3/statements/schema/AlterTableStatement.java:672

            if (modeChange && next.transactionalMode.accordIsEnabled && !DatabaseDescriptor.getAccordTransactionsEnabled())
                throw ire(format("Cannot change transactional mode to %s for %s.%s with accord.enabled set to false",
                                 next.transactionalMode, keyspaceName, tableName));

            // user is manually updating migration mode, don't interfere
            if (forceMigrationChange)
            {
                logger.warn("Forcing unsafe migration change from {} to {} with transaction mode {}", prev.transactionalMigrationFrom, next.transactionalMigrationFrom, next.transactionalMode);
                return next;
            }

            if (!modeChange)
                return next;

            // if the user is trying to revert to the mode being migrated from, allow it. The migration states will be inverted when
            // the transformation is applied. Otherwise throw
            if (wasMigrating && next.transactionalMode != prev.transactionalMigrationFrom.from)
                throw ire(format("Cannot change transactional mode from %s to %s for %s.%s before transactional migration has completed",
                                 prev.transactionalMode, next.transactionalMode,
                                 keyspaceName, tableName));

            return next.unbuild().transactionalMigrationFrom(newMigrateFrom).build();
        }

        @Override
        public boolean compatibleWith(ClusterMetadata metadata)
        {
            return metadata.directory.commonSerializationVersion.isAtLeast(Version.V0);
        }

        public KeyspaceMetadata apply(Epoch epoch, KeyspaceMetadata keyspace, TableMetadata table, ClusterMetadata metadata)
        {
            attrs.validate();

            TableParams params = attrs.asAlteredTableParams(table.params);

View on GitHub (pinned to 88fd0f6a0e)