apache/cassandra · error · ConfigurationException

Can't add full replicas if there are any transient replicas.

Error message

Can't add full replicas if there are any transient replicas. You must first remove all transient replicas, then change the # of full replicas, then add back the transient replicas

What it means

Transient replication does not support a direct transition from more full replicas with existing transients to fewer full replicas: the transient->full transition lacks the pending state needed for correctness, so a read could hit a transient replica as if it were a full one. The change must be done stepwise.

Source

Thrown at src/java/org/apache/cassandra/cql3/statements/schema/AlterKeyspaceStatement.java:217

        if (newTrans > 0)
        {
            if (DatabaseDescriptor.getNumTokens() > 1)
                throw new ConfigurationException(String.format("Transient replication is not supported with vnodes yet"));


            if (!current.views.isEmpty())
                throw new ConfigurationException("Cannot use transient replication on keyspaces using materialized views");

            for (TableMetadata table : current.tables)
                if (!table.indexes.isEmpty())
                    throw new ConfigurationException("Cannot use transient replication on keyspaces using secondary indexes");
        }

        //This is true right now because the transition from transient -> full lacks the pending state
        //necessary for correctness. What would happen if we allowed this is that we would attempt
        //to read from a transient replica as if it were a full replica.
        if (oldFull > newFull && oldTrans > 0)
            throw new ConfigurationException("Can't add full replicas if there are any transient replicas. You must first remove all transient replicas, then change the # of full replicas, then add back the transient replicas");

        //Don't increase transient replication factor by more than one at a time if changing number of replicas
        //Just like with changing full replicas it's not safe to do this as you could read from too many replicas
        //that don't have the necessary data. W/O transient replication this alteration was allowed and it's not clear
        //if it should be.
        //This is structured so you can convert as many full replicas to transient replicas as you want.
        boolean numReplicasChanged = oldTrans + oldFull != newTrans + newFull;
        if (numReplicasChanged && (newTrans > oldTrans && newTrans != oldTrans + 1))
            throw new ConfigurationException("Can only safely increase number of transients one at a time with incremental repair run in between each time");
    }

    @Override
    public AuditLogContext getAuditLogContext()
    {
        return new AuditLogContext(AuditLogEntryType.ALTER_KEYSPACE, keyspaceName);
    }

    public String toString()

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. First remove all transient replicas (e.g. '3/1' -> '3/0'), run incremental repair, then change full RF ('3/0' -> '2/0' or target), then re-add transients one at a time with repair between steps.
  2. Follow the documented multi-step sequence; verify with an incremental repair after each step.
  3. Avoid mixing full-RF changes and transient-RF changes in a single ALTER KEYSPACE.

Example fix

// before (one step)
"ALTER KEYSPACE ks WITH replication = {'dc1':'3/1'}"; // from '2/1'
// after (staged)
"ALTER KEYSPACE ks WITH replication = {'dc1':'2/0'}"; runIncrementalRepair();
"ALTER KEYSPACE ks WITH replication = {'dc1':'3/0'}"; runIncrementalRepair();
"ALTER KEYSPACE ks WITH replication = {'dc1':'3/1'}";
Defensive patterns

Strategy: validation

Validate before calling

if (oldFull > newFull && oldTrans > 0) throw new IllegalArgumentException("stage the RF change: remove transients first, repair, then change full RF");

Try / catch

try { session.execute(alterKeyspace); } catch (ConfigurationException e) { if (e.getMessage().contains("Can't add full replicas if there are any transient replicas")) applyStagedReplicationChange(current, target); else throw e; }

Prevention

When it happens

Trigger: `ALTER KEYSPACE ks WITH replication = {'dc1':'2/1' -> '3/1'}` style change where oldFull > newFull and oldTrans > 0 — i.e. adding full replicas while transient replicas still exist.

Common situations: Operators trying to rebalance RF in one step on a transient-replication keyspace, e.g. increasing full RF from 2 to 3 while keeping 1 transient replica.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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