apache/cassandra · error · RuntimeException

Replace method removed; use cassandra.replace_address…

Error message

Replace method removed; use cassandra.replace_address instead

What it means

The old token-based and host-id-based replace mechanisms (cassandra.replace_tokens / replace_node properties) were removed. initServer fails fast with a RuntimeException if either legacy setting is populated, directing operators to cassandra.replace_address.

Solutions

  1. Remove cassandra.replace_tokens and cassandra.replace_node from jvm options/cassandra-env.sh
  2. Set -Dcassandra.replace_address=<dead node ip> instead
  3. Audit startup scripts after version upgrades for removed replace flags

Example fix

// before
JVM_OPTS="$JVM_OPTS -Dcassandra.replace_tokens=..."
// after
JVM_OPTS="$JVM_OPTS -Dcassandra.replace_address=10.0.0.5"
Defensive patterns

Strategy: validation

Validate before calling

grep -R 'cassandra.replace_tokens\|cassandra.replace_node' jvm-server.options cassandra-env.sh  # must be empty

Try / catch

try { startNode(); } catch (RuntimeException e) { if (e.getMessage().contains("Replace method removed")) { /* fix startup flags */ } }

Prevention

When it happens

Trigger: Starting a node with DatabaseDescriptor.getReplaceTokens() non-empty or getReplaceNode() set — i.e. cassandra.replace_tokens / cassandra.replace_node (or their yaml equivalents) still configured.

Common situations: Upgrading an old cluster where replace procedures were scripted with legacy flags; copied cassandra-env.sh or jvm-server.options carrying stale -Dcassandra.replace_tokens/-Dcassandra.replace_node entries.

Understand the failure class

Background: "is deprecated and will be removed" — deprecation warnings for old API names, keywords, and options, and how to migrate before the removal release — this error's family across 29 libraries.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/service/StorageService.java:808

            Gossiper.instance.addLocalApplicationState(ApplicationState.SSTABLE_VERSIONS,
                                                       valueFactory.sstableVersions(versions));
        });

        if (SystemKeyspace.wasDecommissioned())
        {
            if (CassandraRelevantProperties.OVERRIDE_DECOMMISSION.getBoolean())
            {
                logger.warn("This node was decommissioned, but overriding by operator request.");
            }
            else
            {
                throw new ConfigurationException("This node was decommissioned and will not rejoin the ring unless cassandra.override_decommission=true has been set, or all existing data is removed and the node is bootstrapped again");
            }
        }

        if (DatabaseDescriptor.getReplaceTokens().size() > 0 || DatabaseDescriptor.getReplaceNode() != null)
            throw new RuntimeException("Replace method removed; use cassandra.replace_address instead");

        if (isReplacing())
        {
            if (SystemKeyspace.bootstrapComplete())
                throw new RuntimeException("Cannot replace with a node that is already bootstrapped");

            InetAddressAndPort replaceAddress = DatabaseDescriptor.getReplaceAddress();
            Directory directory = ClusterMetadata.current().directory;
            if (directory.peerId(replaceAddress) == null || directory.peerState(replaceAddress) != JOINED)
                throw new RuntimeException(String.format("Cannot replace node %s which is not currently joined", replaceAddress));

            BootstrapAndReplace.checkUnsafeReplace(shouldBootstrap());
        }

        if (isReplacingSameAddress())
        {
            BootstrapAndReplace.gossipStateToHibernate(ClusterMetadata.current(), ClusterMetadata.currentNullable().myNodeId());
            Gossiper.instance.start(SystemKeyspace.incrementAndGetGeneration(), false);

View on GitHub (pinned to 88fd0f6a0e)