{"record":{"id":"b485efa7122a5876","repo":"apache/cassandra","slug":"cannot-replace-a-live-node","errorCode":null,"errorMessage":"Cannot replace a live node... ","messagePattern":"Cannot replace a live node\\.\\.\\. ","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/tcm/Startup.java","lineNumber":737,"sourceCode":"\n    /**\n     * Returns:\n     *   * {@link PrepareReplace}, the first step of the multi-step replacement process sequence, if {@param finishJoiningRing} is true\n     *   * {@link UnsafeJoin}, a single-step join transformation, if {@param shouldBootstrap} is set to false, and the node is not\n     *     in a write survey mode (in other words {@param finishJoiningRing} is true. This mode is mostly used for testing, but can\n     *     also be used to quickly set up a fresh cluster.\n     *   * and {@link PrepareJoin}, the first step of the multi-step join process, otherwise.\n     */\n    private static Transformation getInitialTransformation(boolean finishJoiningRing, boolean shouldBootstrap, boolean isReplacing)\n    {\n        ClusterMetadata metadata = ClusterMetadata.current();\n        if (isReplacing)\n        {\n            InetAddressAndPort replacingEndpoint = DatabaseDescriptor.getReplaceAddress();\n            if (FailureDetector.instance.isAlive(replacingEndpoint))\n            {\n                logger.error(\"Unable to replace live node {})\", replacingEndpoint);\n                throw new UnsupportedOperationException(\"Cannot replace a live node... \");\n            }\n\n            NodeId replaced = ClusterMetadata.current().directory.peerId(replacingEndpoint);\n\n            return new PrepareReplace(replaced,\n                                      metadata.myNodeId(),\n                                      ClusterMetadataService.instance().placementProvider(),\n                                      finishJoiningRing,\n                                      shouldBootstrap);\n        }\n        else if (finishJoiningRing && !shouldBootstrap)\n        {\n            return new UnsafeJoin(metadata.myNodeId(),\n                                  new HashSet<>(BootStrapper.getBootstrapTokens(ClusterMetadata.current(), getBroadcastAddressAndPort())),\n                                  ClusterMetadataService.instance().placementProvider());\n        }\n        else\n        {","sourceCodeStart":719,"sourceCodeEnd":755,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/tcm/Startup.java#L719-L755","documentation":"When this node is configured to replace another node, Startup checks the replace target's liveness via the FailureDetector; if the target is considered alive, replacement is refused with UnsupportedOperationException because replacing a live node would fork cluster state and data ownership.","triggerScenarios":"cassandra.replace_address set to a host that the FailureDetector currently reports as alive (isAlive returns true) when getInitialTransformation builds the PrepareReplace step.","commonSituations":"Typo in cassandra.replace_address pointing at a healthy node; the target node actually restarted and is healthy; gossip/failure-detector stale state briefly marking a dead node alive; automation misconfiguring replacement variables.","solutions":["Verify the replace target is truly down; wait until FailureDetector marks it dead (check nodetool gossipinfo / status)","Correct cassandra.replace_address if it points at the wrong node","Restart this node once the target is confirmed dead (the check runs at startup only)","If a liveness false-positive persists, inspect network/phi-conviction threshold settings"],"exampleFix":"// before\ncassandra.replace_address=10.0.0.7   # still alive\n// after\n# confirm 10.0.0.7 is down, then\ncassandra.replace_address=10.0.0.7   # marked dead by failure detector","handlingStrategy":"validation","validationCode":"if (FailureDetector.instance.isAlive(InetAddressAndPort.getByNameByName(replaceAddress)))\n    throw new IllegalArgumentException(\"Replace target is still alive\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Confirm the target is powered off and unreachable before setting cassandra.replace_address","Double-check replace_address against cluster state (nodetool status) to avoid typos","Serialize replacement ops so the target cannot restart concurrently"],"tags":["replace-address","failure-detector","startup","configuration"],"backgroundTag":"invalid-argument-value","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"}