{"record":{"id":"cc576eead45f2cdd","repo":"apache/cassandra","slug":"expected-to-complete-startup-sequence-but-did-not","errorCode":null,"errorMessage":"Expected to complete startup sequence, but did not. Can't proceed from the state ","messagePattern":"Expected to complete startup sequence, but did not\\. Can't proceed from the state ","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/tcm/Startup.java","lineNumber":703,"sourceCode":"                {\n                    if (DatabaseDescriptor.getAccordTransactionsEnabled())\n                    {\n                        // TODO (required): we need to support a mode that changes the NodeId when replacing the same address for accord transaction safety\n                        throw new IllegalStateException(\"Cannot replace same address when accord transactions are enabled.\");\n                    }\n\n                    ReplaceSameAddress.streamData(self, metadata, shouldBootstrap, finishJoiningRing);\n                }\n\n                // JOINED appears before BOOTSTRAPPING & BOOT_REPLACE so we can fall\n                // through when we start as REGISTERED/LEFT and complete a full startup\n                logger.info(\"{}\", StorageService.Mode.NORMAL);\n                break;\n            case BOOTSTRAPPING:\n            case BOOT_REPLACING:\n                if (finishJoiningRing)\n                {\n                    throw new IllegalStateException(\"Expected to complete startup sequence, but did not. \" +\n                                                    \"Can't proceed from the state \" + metadata.directory.peerState(self));\n                }\n                break;\n            case LEAVING:\n                logger.info(\"Node is currently being decommissioned, resume with `nodetool decommission`\");\n                StorageService.instance.markDecommissionFailed();\n                break;\n            case MOVING:\n                logger.info(\"Node is currently moving, resume with nodetool move --resume or abort with nodetool move --abort\");\n                StorageService.instance.markMoveFailed();\n                break;\n            default:\n                throw new IllegalStateException(\"Can't proceed from the state \" + metadata.directory.peerState(self));\n        }\n    }\n\n    /**\n     * Returns:","sourceCodeStart":685,"sourceCodeEnd":721,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/tcm/Startup.java#L685-L721","documentation":"Startup.java's resume logic, when finishJoiningRing is true, expects the node to be past its bootstrap/boot-replace phase; if ClusterMetadata still shows the peer (this node) in BOOTSTRAPPING or BOOT_REPLACING state, the invariant 'startup sequence should have completed' is broken and it throws IllegalStateException.","triggerScenarios":"Calling Startup.startup (or StorageService.initServer) with finishJoiningRing=true on a node whose ClusterMetadata peer state is BOOTSTRAPPING or BOOT_REPLACING — i.e. a half-finished bootstrap/replace being resumed as if it were already complete.","commonSituations":"Interrupted bootstrap (crash or kill mid-join) followed by a restart with flags that force completion of the join ring; automation tools re-running startup with wrong options after a failed bootstrap.","solutions":["Restart with finishJoiningRing=false so the node resumes the in-progress bootstrap/boot-replace sequence","Let the multi-step operation resume via nodetool (or abort it: nodetool abortbootstrap/decommission as appropriate) instead of forcing NORMAL","Inspect ClusterMetadata peer state (nodetool / tcm metadata) to confirm actual state before retrying","Wipe data and re-bootstrap cleanly if the partial bootstrap is unrecoverable"],"exampleFix":"// before\nStartup.startup(finishJoiningRing = true)\n// after\nStartup.startup(finishJoiningRing = false) // resume in-progress BOOTSTRAPPING first","handlingStrategy":"try-catch","validationCode":"// before forced startup\nNodeState s = ClusterMetadata.current().directory.peerState(self);\nif ((s == NodeState.BOOTSTRAPPING || s == NodeState.BOOT_REPLACING) && finishJoiningRing)\n    finishJoiningRing = false;","typeGuard":null,"tryCatchPattern":"try { Startup.startup(...); }\ncatch (IllegalStateException e) {\n    if (e.getMessage().contains(\"Can't proceed from the state\")) {\n        // resume with finishJoiningRing=false or abort the in-progress op\n    } else throw e;\n}","preventionTips":["Always resume interrupted bootstraps with finishJoiningRing=false first","Check peer state in ClusterMetadata before forcing startup flags","Automate bootstrap recovery rather than hard-coding startup options"],"tags":["tcm","bootstrap","startup","state-machine"],"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-14T11:17:12.474Z"}