apache/cassandra · error · ConfigurationException

Can only safely increase number of transients one at a time

Error message

Can only safely increase number of transients one at a time with incremental repair run in between each time

What it means

When the total replica count changes and transient replicas are being increased, Cassandra only allows increasing transients by exactly one at a time, requiring an incremental repair between increases, because un-repaired ranges on new transient replicas could be read unsafely.

Source

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

            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()
    {
        return String.format("%s (%s)", getClass().getSimpleName(), keyspaceName);
    }

    public static final class Raw extends CQLStatement.Raw
    {
        private final String keyspaceName;
        private final KeyspaceAttributes attrs;
        private final boolean ifExists;

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Increase transient replicas one at a time: '3/0' -> '3/1', run incremental repair, then '3/1' -> '3/2'.
  2. Run `nodetool repair -inc` on the keyspace after each single increment.
  3. If total replica count is unchanged, convert full->transient freely; otherwise follow the one-at-a-time rule.

Example fix

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

Strategy: validation

Validate before calling

boolean numReplicasChanged = oldTrans + oldFull != newTrans + newFull; if (numReplicasChanged && newTrans > oldTrans && newTrans != oldTrans + 1) throw new IllegalArgumentException("increase transients by exactly 1 per step with repair between");

Try / catch

try { session.execute(alterKeyspace); } catch (ConfigurationException e) { if (e.getMessage().contains("increase number of transients one at a time")) applyOneTransientAtATime(target); else throw e; }

Prevention

When it happens

Trigger: `ALTER KEYSPACE ks WITH replication = {'dc1':'3/0' -> '3/2'}` (transients increased by 2 in one step) while the total replica count also changed.

Common situations: Operators jumping transient RF from 0 to 2 (or similar multi-step jump) to save capacity quickly, without running incremental repair between each increment.

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/d19d231bbab23b2d. Report an issue: GitHub.