{"record":{"id":"bc155c2bf0ba10cf","repo":"apache/cassandra","slug":"transaction-statement-is-unsupported-when-migratin","errorCode":null,"errorMessage":"Transaction Statement is unsupported when migrating away from Accord or before migration to Accord is complete for a range","messagePattern":"Transaction Statement is unsupported when migrating away from Accord or before migration to Accord is complete for a range","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/statements/TransactionStatement.java","lineNumber":609,"sourceCode":"        // check again since now we have query options; note that statements are quaranted to be single partition reads at this point\n        for (NamedSelect assignment : assignments)\n        {\n            checkFalse(isSelectingMultipleClusterings(assignment.select, options), INCOMPLETE_PRIMARY_KEY_SELECT_MESSAGE, \"LET assignment\", assignment.select.source);\n            if (assignment.select.getRestrictions().keyIsInRelation())\n                checkTrue(assignment.select.getLimit(options) == DataLimits.NO_LIMIT, NO_PARTITION_IN_CLAUSE_WITH_LIMIT, \"SELECT\", assignment.select.source);\n        }\n        if (returningSelect != null && returningSelect.select.getRestrictions().keyIsInRelation())\n        {\n            checkTrue(returningSelect.select.getLimit(options) == DataLimits.NO_LIMIT, NO_PARTITION_IN_CLAUSE_WITH_LIMIT, \"SELECT\", returningSelect.select.source);\n        }\n\n        Txn txn = createTxn(state.getClientState(), options);\n        if (txn == null)\n            return new ResultMessage.Void();\n\n        TxnResult txnResult = AccordService.instance().coordinate(minEpoch, txn, options.getConsistency(), requestTime);\n        if (txnResult.kind() == retry_new_protocol)\n            throw new InvalidRequestException(UNSUPPORTED_MIGRATION);\n        TxnValidationRejection.maybeThrow(txnResult);\n        TxnDataResult data = (TxnDataResult)txnResult;\n\n        if (returningSelect != null)\n        {\n            @SuppressWarnings(\"unchecked\")\n            SinglePartitionReadQuery.Group<SinglePartitionReadCommand> selectQuery = (SinglePartitionReadQuery.Group<SinglePartitionReadCommand>) returningSelect.select.getQuery(options, 0);\n            Selection.Selectors selectors = returningSelect.select.getSelection().newSelectors(options);\n            long atMicros = data.atMicros;\n            FunctionContext context = new FunctionContext.MicrosFunctionContext(atMicros)\n            {\n                @Override public QueryOptions options() { return options; }\n            };\n            ResultSetBuilder result = new ResultSetBuilder(resultMetadata, context, selectors, false);\n            long atSeconds = atMicros / 1000_000;\n            if (selectQuery.queries.size() == 1)\n            {\n                TxnDataKeyValue partition = (TxnDataKeyValue)data.get(txnDataName(RETURNING));","sourceCodeStart":591,"sourceCodeEnd":627,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/statements/TransactionStatement.java#L591-L627","documentation":"TransactionStatement.execute() coordinates an Accord transaction; when AccordService.coordinate() returns a TxnResult of kind retry_new_protocol, the protocol cannot serve the transaction for the current epoch/range (either Accord migration has not completed for the range, or the cluster is migrating away from Accord), and the statement throws InvalidRequestException with UNSUPPORTED_MIGRATION text.","triggerScenarios":"Running BEGIN TRANSACTION ... statements while the cluster is in a state where Accord is disabled/partially migrated (e.g. before the Accord migration has been driven to completion for the token range, or during a migration-away procedure), causing coordinate() to answer retry_new_protocol.","commonSituations":"Testing transactional CQL on a cluster where accord is not enabled via feature flags/config; upgrading/rolling back across a version boundary that changes Accord participation; issuing transactions immediately after node bootstrap before epoch/migration state converges.","solutions":["Enable/complete the Accord migration for the cluster (accord config and migration tooling) before issuing transaction statements","Retry after migration state converges (retry_new_protocol indicates protocol timing)","Use standard (non-transactional) CQL statements if Accord is intentionally disabled","Check cluster epoch/migration status (AccordService/jmx logs) to confirm the range is on the Accord protocol"],"exampleFix":"// before (accord not migrated)\nBEGIN TRANSACTION\n  SELECT ... ;\nCOMMIT TRANSACTION;\n// after\n-- either enable/complete Accord migration in cassandra.yaml,\n-- or use plain statements:\nSELECT ... FROM ks.t WHERE ...;","handlingStrategy":"retry","validationCode":"if (!clusterAccordMigrationComplete()) throw new Error('Accord not ready for transaction statements; use plain CQL');","typeGuard":null,"tryCatchPattern":"try { session.execute(txnStmt); } catch (e) { if (/migrat.*Accord/.test(e.message)) { await waitForAccordEpochConvergence(); return session.execute(txnStmt); } throw e; }","preventionTips":["Only issue BEGIN TRANSACTION statements after Accord migration is complete cluster-wide","Gate transactional paths on cluster/epoch readiness checks","Fall back to non-transactional CQL when Accord is disabled for a range"],"tags":["cql","accord","transactions","migration"],"backgroundTag":"unsupported-operation","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}