apache/cassandra · error · InvalidRequestException

cannot transition to at ; current

Error message

cannot transition %s to %s at %s; current %s

What it means

AccordFastPath.withNodeStatusSince validates node status transitions against canUpdateNodeTo before mutating the fast-path info map. The requested transition (e.g. re-reporting an older status, or going backwards in time/delay constraints) is rejected and thrown as an InvalidRequestException. This enforces the state machine that keeps fast-path node health monotonic.

Solutions

  1. Check the current status and timestamps (via the fast-path info map) before issuing the transition.
  2. Discard stale status reports whose updateTimeMillis is older than the recorded update.
  3. Ensure only one coordinator applies transitions, or make the update idempotent by tolerating no-op transitions instead of throwing.
  4. Log the current NodeInfo from the exception message to determine which transition rule was violated.
Defensive patterns

Strategy: validation

Validate before calling

// check the transition is legal before calling
NodeInfo current = info.get(node);
if (current != null && !canUpdateNodeTo(current, newStatus, updateTimeMillis, updateDelayMillis))
    return; // skip stale/illegal transition instead of throwing

Try / catch

try {
    fastPath = fastPath.withNodeStatusSince(node, status, sinceMillis, updateDelayMillis);
} catch (InvalidRequestException e) {
    logger.debug("Skipping stale node status update: {}", e.getMessage());
    // treat as no-op; state has already moved forward
}

Prevention

When it happens

Trigger: Calling withNodeStatusSince(node, status, updateTimeMillis, updateDelayMillis) where canUpdateNodeTo(current, status, ...) returns false — e.g. updating a node to a status that regresses from current, or with a timestamp/delay that violates transition rules.

Common situations: Out-of-order or stale status reports arriving after a node already transitioned (e.g. a late UNAVAILABLE report after the node came back NORMAL); misconfigured update delays in topology management code; concurrent coordinators racing to update node status.

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

Appendix: source

Thrown at src/java/org/apache/cassandra/service/accord/topology/AccordFastPath.java:207

        ImmutableMap.Builder<Node.Id, NodeInfo> builder = ImmutableMap.builder();
        info.forEach((n, info) -> {
            if (!n.equals(node))
                builder.put(n, info);
        });
        return new AccordFastPath(builder.build(), lastModified);
    }

    public AccordFastPath withNodeStatusSince(Node.Id node, Status status, long updateTimeMillis, long updateDelayMillis)
    {
        NodeInfo current = info.get(node);
        if (status == Status.SHUTDOWN && current != null)
        {
            // nodes report when they're being shutdown and aren't superseded
            updateTimeMillis = Math.max(updateTimeMillis, current.updated + 1);
        }

        if (!canUpdateNodeTo(current, status, updateTimeMillis, updateDelayMillis))
            throw new InvalidRequestException(String.format("cannot transition %s to %s at %s; current %s", node, status, updateTimeMillis, current));

        ImmutableMap.Builder<Node.Id, NodeInfo> builder = ImmutableMap.builder();
        builder.put(node, new NodeInfo(status, updateTimeMillis));
        info.forEach((n, info) -> {
            if (!n.equals(node))
                builder.put(n, info);
        });
        return new AccordFastPath(builder.build(), lastModified);
    }

    public boolean canUpdateNodeTo(NodeInfo current, Status status, long updateTimeMillis, long updateDelayMillis)
    {
        if (current == null)
            return status != Status.NORMAL;

        if (current.status == status)
            return false;

View on GitHub (pinned to 88fd0f6a0e)