apache/cassandra · error · InvalidRequestException
Attempted to serve data request from node in
Error message
Attempted to serve %s data request from %s node in %s
What it means
ReadCommandVerbHandler.checkTokenOwnership rejects a data request when the only local replica for the requested token is a transient replica but the read command requires full data (does not accept transient reads). Serving full reads from a transient replica would violate read consistency, so the message is dropped as invalid request.
Solutions
- Fix replication so every range has enough full replicas (complete pending bootstrap/decommission, run repair)
- Retry the read via a coordinator that routes to a full replica
- Verify the coordinator's token map is current (restart or wait for gossip/metadata convergence)
- If transient replication is not intended, ensure the read/command consistency and options do not rely on transient ranges
Defensive patterns
Strategy: validation
Validate before calling
// before relying on reads on a node
NodeToolOutput status = nodetool("info");
if (clusterHasPendingOrLeavingNodes(status)) {
// ranges may be served by transient replicas; finish topology ops first
throw new PreconditionFailed("complete bootstrap/decommission before reads");
} Prevention
- Complete bootstrap/decommission and run repair before normal reads
- Verify every range has the configured number of FULL replicas
- Keep coordinator token maps current; avoid reading through freshly restarted coordinators until gossip settles
- Monitor for transient-only ranges in your topology tooling
When it happens
Trigger: A coordinator routes a full (non-transient) read for a token to a node that only holds that range as a transient replica (e.g., RF lacks a full replica due to pending/decommissioning nodes), and doVerb -> checkTokenOwnership detects localReplica.isTransient().
Common situations: Cluster running with transient replication enabled while a node is still being bootstrapped or decommissioned; coordinator ring cache stale after topology change; misconfigured rack/DC leaving a range covered only by transient replicas.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- A storage-attached index cannot be created over multiple…
- A TTL must be greater or equal to 0, but was
- Accord transaction uses dropped tables
- All arguments must have the same vector dimensions
- Amount of transient nodes should be strictly positive, but…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/155dc506a319ddc3.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/db/ReadCommandVerbHandler.java:203
{
Token token = ((SinglePartitionReadCommand)command).partitionKey().getToken();
Replica localReplica = getLocalReplica(metadata, token, command.metadata().keyspace);
if (localReplica == null)
{
metadata = ClusterMetadataService.instance().fetchLogFromPeerOrCMS(metadata, message.from(), message.epoch());
localReplica = getLocalReplica(metadata, token, command.metadata().keyspace);
}
if (localReplica == null)
{
StorageService.instance.incOutOfRangeOperationCount();
Keyspace.open(command.metadata().keyspace).metric.outOfRangeTokenReads.inc();
throw InvalidRoutingException.forTokenRead(message.from(), token, metadata.epoch, message.payload);
}
if (!command.acceptsTransient() && localReplica.isTransient())
{
MessagingService.instance().metrics.recordDroppedMessage(message, message.elapsedSinceCreated(NANOSECONDS), NANOSECONDS);
throw new InvalidRequestException(String.format("Attempted to serve %s data request from %s node in %s",
command.acceptsTransient() ? "transient" : "full",
localReplica.isTransient() ? "transient" : "full",
this));
}
}
else
{
AbstractBounds<PartitionPosition> range = ((PartitionRangeReadCommand) command).dataRange().keyRange();
// TODO: preexisting issue: for the range queries or queries that span multiple replicas, we can only make requests where the right token is owned, but not the left one
Replica maxTokenLocalReplica = getLocalReplica(metadata, range.right.getToken(), command.metadata().keyspace);
if (maxTokenLocalReplica == null)
{
metadata = ClusterMetadataService.instance().fetchLogFromPeerOrCMS(metadata, message.from(), message.epoch());
maxTokenLocalReplica = getLocalReplica(metadata, range.right.getToken(), command.metadata().keyspace);
}
if (maxTokenLocalReplica == null)
{View on GitHub (pinned to 88fd0f6a0e)