{"record":{"id":"ffdcba87a7d440b4","repo":"apache/cassandra","slug":"error-occurred-attempting-to-finish-migration-for","errorCode":null,"errorMessage":"Error occurred attempting to finish migration for keyspace(s) %s tables %s and ranges %s","messagePattern":"Error occurred attempting to finish migration for keyspace\\(s\\) (.+?) tables (.+?) and ranges (.+?)","errorType":"console","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/tools/nodetool/ConsensusMigrationAdmin.java","lineNumber":174,"sourceCode":"            List<RepairCmd> repairCmds = new ArrayList<>(keyspaceNames.size() * 2);\n            // Finish can't actually finish with one set of repairs when migrating from Paxos -> Accord\n            // and it's async when the next invocation will see TCM updates from the repair that will correctly determine\n            // the next set of repairs needed. If we spin we will issue redundant repairs.\n            // It's also pretty involved not to return handles on the repairs since there is already a lot of plumbing\n            // leveraging monitoring in progress repairs.\n            output.out.println(\"Starting first round of repairs\");\n            for (String keyspace : keyspaceNames)\n            {\n                repairCmds.add(new FinishMigrationRepairCommand(probe, keyspace, maybeTableNames, maybeRangesStr, ConsensusMigrationTarget.paxos));\n                repairCmds.add(new FinishMigrationRepairCommand(probe, keyspace, maybeTableNames, maybeRangesStr, ConsensusMigrationTarget.accord));\n            }\n            try\n            {\n                probe.startAndBlockOnAsyncRepairs(probe.output().out, repairCmds);\n            }\n            catch (IOException e)\n            {\n                throw new RuntimeException(\"Error occurred attempting to finish migration for keyspace(s) \" + keyspaceNames + \" tables \" + maybeTableNames + \" and ranges \" + maybeRangesStr, e);\n            }\n            // The repair should have at least committed the TCM change to the node we asked to coordinate the repair\n            // so calling finishedConsensusMigration a second time should trigger any needed 2nd phase repairs\n            // or does nothing if none are needed\n            output.out.println(\"Starting second round of repairs (may do nothing if migrating from Accord to Paxos)\");\n            repairCmds.clear();\n            for (String keyspace : keyspaceNames)\n            {\n                repairCmds.add(new FinishMigrationRepairCommand(probe, keyspace, maybeTableNames, maybeRangesStr, ConsensusMigrationTarget.accord));\n            }\n            try\n            {\n                probe.startAndBlockOnAsyncRepairs(probe.output().out, repairCmds);\n            }\n            catch (IOException e)\n            {\n                throw new RuntimeException(\"Error occurred attempting to finish migration for keyspace(s) \" + keyspaceNames + \" tables \" + maybeTableNames + \" and ranges \" + maybeRangesStr, e);\n            }","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/tools/nodetool/ConsensusMigrationAdmin.java#L156-L192","documentation":"ConsensusMigrationAdmin's execute launches the repair rounds that finish a Paxos-to-Accord (or reverse) consensus migration via probe.startAndBlockOnAsyncRepairs; an IOException there is wrapped with a message naming the keyspaces, tables, and ranges involved. It means the blocking async-repair phase of the migration failed at the transport/remote level.","triggerScenarios":"Running `nodetool adminconsensusmigration finish`-style migration completion when the JMX connection drops, repair coordination fails, or a targeted node is down during startAndBlockOnAsyncRepairs.","commonSituations":"Node loss during migration repair; JMX timeouts because repairs take longer than the connection tolerates; ranges computed from an outdated ring after topology change.","solutions":["Ensure all nodes in the migration ranges are up and reachable, then re-run the finish command (it is idempotent — a second call does nothing if repairs already committed).","Check repair history / logs (`nodetool netstats`, system protocol logs) for the failing range.","Retry the command; TCM-committed changes are durable and the second round is safe to repeat.","Inspect the wrapped IOException cause for connection-level details."],"exampleFix":"// before\nnodetool adminconsensusmigration finish ks  # node down mid-repair\n// after\nnodetool status  # all nodes Up\nnodetool adminconsensusmigration finish ks  # safe to re-run","handlingStrategy":"retry","validationCode":"// preflight: all nodes Up and JMX reachable\nif (!allNodesUp(probe)) throw new IllegalStateException(\"Cannot finish migration with nodes down\");","typeGuard":null,"tryCatchPattern":"try {\n    probe.startAndBlockOnAsyncRepairs(out, repairCmds);\n}\ncatch (IOException e) {\n    log(\"Migration finish failed for \" + keyspaces + \"; TCM changes are durable — safe to re-run after nodes recover\");\n    retryWithBackoff(() -> probe.startAndBlockOnAsyncRepairs(out, repairCmds));\n}","preventionTips":["Verify nodetool status shows all nodes Up before finishing migration.","Allow generous JMX timeouts — blocking on repairs can be long-running.","Re-run the finish command after transient failures; the second round is idempotent.","Monitor repair progress and migration state via protocol change logs."],"tags":["nodetool","consensus","migration","repair","jmx"],"backgroundTag":"api-request-failed","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"}