apache/cassandra · error · InvalidRequestException

Can't route consensus request to nonexistent CFS %s.%s

Error message

Can't route consensus request to nonexistent CFS %s.%s

What it means

During Paxos-to-Accord consensus migration, the router must resolve the table's ColumnFamilyStore (CFS) instance to route a consensus request. If the CFS cannot be found by table ID at routing time, the table has been dropped or is not yet/ no longer present in this node's local schema, and Cassandra throws this InvalidRequestException rather than route to a nonexistent store.

Source

Thrown at src/java/org/apache/cassandra/service/consensus/migration/ConsensusRequestRouter.java:244

        if (tms.migratingRanges.intersects(token))
            return pickBasedOnKeyMigrationStatus(cm, tmd, tms, key, consistencyLevel, requestTime, timeoutNanos, isForWrite);

        // It's not migrated so infer the protocol from the target
        return pickNotMigrated(tms.targetProtocol);
    }

    /**
     * If the key was already migrated then we can pick the target protocol otherwise
     * we have to run a repair operation on the key to migrate it.
     */
    private static ConsensusRoutingDecision pickBasedOnKeyMigrationStatus(ClusterMetadata cm, TableMetadata tmd, TableMigrationState tms, DecoratedKey key, ConsistencyLevel consistencyLevel, Dispatcher.RequestTime requestTime, long timeoutNanos, boolean isForWrite)
    {
        checkState(pickPaxos() != ConsensusRoutingDecision.PAXOSV1, "Can't migrate from PaxosV1 to anything");

        ColumnFamilyStore cfs = ColumnFamilyStore.getIfExists(tmd.id);
        if (cfs == null)
            throw new InvalidRequestException("Can't route consensus request to nonexistent CFS %s.%s".format(tmd.keyspace, tmd.name));

        // Migration to accord has two phases for each range, in the first phase we can't do key migration because Accord
        // can't safely read until the range has had its data repaired so Paxos continues to be used for all reads
        // and writes
        Token token = key.getToken();
        if (tms.targetProtocol == ConsensusMigrationTarget.accord && tms.repairPendingRanges.intersects(token))
            return pickPaxos();

        // If it is locally replicated we can check our local migration state to see if it was already migrated
        EndpointsForToken naturalReplicas = ReplicaLayout.forNonLocalStrategyTokenRead(cm, cfs.keyspace.getMetadata(), token);
        boolean isLocallyReplicated = naturalReplicas.lookup(FBUtilities.getBroadcastAddressAndPort()) != null;
        if (isLocallyReplicated)
        {
            ConsensusMigratedAt consensusMigratedAt = getConsensusMigratedAt(tms.tableId, key);
            // Check that key migration that was performed satisfies the requirements of the current in flight migration
            // for the range
            // Be aware that for Accord->Paxos the cache only tells us if the key was repaired locally
            // This ends up still being safe because every single Paxos read (in a migrating range) during migration will check

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Check that the table still exists (system_schema.tables / DESCRIBE) and re-create it if it was dropped unintentionally
  2. Retry the operation on a different node or after schema agreement is reached (nodetool checkschemaversions)
  3. Clear stale client state: re-prepare statements against the live table
  4. If it occurs during rolling restarts, ensure the node has fully completed startup and CFS construction before serving traffic

Example fix

// before: blind retry loop on InvalidRequestException
session.execute(lwtInsert);
// after: guard against dropped table
try {
    session.execute(lwtInsert);
} catch (InvalidRequestException e) {
    if (schema.tableExists(keyspace, table)) throw e;
    // table was dropped; skip or recreate
}
Defensive patterns

Strategy: validation

Validate before calling

Row row = session.execute("SELECT table_name FROM system_schema.tables WHERE keyspace_name=? AND table_name=?", ks, table).one();
if (row == null) throw new IllegalStateException("Table " + ks + "." + table + " does not exist");

Try / catch

try { session.execute(lwt); } catch (InvalidRequestException e) { /* table likely dropped; refresh schema metadata and re-check */ session.refreshSchema(); }

Prevention

When it happens

Trigger: A client sends a serial/consensus (LWT or transactional) read or write to a table whose schema metadata still exists in ClusterMetadata but whose local ColumnFamilyStore lookup (ColumnFamilyStore.getIfExists(tmd.id)) returns null — typically the table was dropped concurrently, or the node's local CFS has not been created/not yet initialized for that table.

Common situations: Race between dropping a table and in-flight LWT/transactional requests hitting it; schema disagreement where one node knows the drop and another still routes; requests arriving during node startup before all CFS instances are constructed; stale prepared statements referencing a dropped table.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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