apache/cassandra · error · Paxos.MaybeFailure

Operation timed out

Error message

Operation timed out

What it means

During the Paxos proposal phase, a MAYBE result means the coordinator cannot determine whether its update was applied — a competing ballot may have completed the proposal. Cassandra surfaces this uncertainty as a WriteTimeoutException ('Operation timed out') marked as a timeout rather than a failure, telling the client the result is unknown and must be resolved.

Source

Thrown at src/java/org/apache/cassandra/service/paxos/Paxos.java:955

                    default: throw new IllegalStateException();
                    case MAYBE_FAILURE:
                        throw propose.maybeFailure().markAndThrowAsTimeoutOrFailure(false, consistencyForConsensus, failedAttemptsDueToContention);

                    case SUCCESS:
                        return serialReadResult(begin.readResponse);

                    case SUPERSEDED:
                        Superseded superseded = propose.superseded();
                        // TODO https://issues.apache.org/jira/browse/CASSANDRA-18276 side effects shouldn't matter for reads
                        switch (superseded.hadSideEffects)
                        {
                            default: throw new IllegalStateException();

                            case MAYBE:
                                // We don't know if our update has been applied, as the competing ballot may have completed
                                // our proposal.  We yield our uncertainty to the caller via timeout exception.
                                // TODO: should return more useful result to client, and should also avoid this situation where possible
                                throw new MaybeFailure(false, begin.participants.sizeOfPoll(), begin.participants.sizeOfConsensusQuorum, 0, emptyMap())
                                      .markAndThrowAsTimeoutOrFailure(true, consistencyForConsensus, failedAttemptsDueToContention);

                            case NO:
                                minimumBallot = propose.superseded().by;
                                // We have been superseded without our proposal being accepted by anyone, so we can safely retry
                                Tracing.trace("Paxos proposal not accepted (pre-empted by a higher ballot)");
                                if (!waitForContention(deadline, ++failedAttemptsDueToContention, group.metadata(), group.queries.get(0).partitionKey(), consistencyForConsensus, READ))
                                    throw MaybeFailure.noResponses(begin.participants).markAndThrowAsTimeoutOrFailure(true, consistencyForConsensus, failedAttemptsDueToContention);
                        }
                        break;
                }
            }
        }
        finally
        {
            // We don't base latency tracking on the startedAtNanos of the RequestTime because queries which involve
            // internal paging may be composed of multiple distinct reads, whereas RequestTime relates to the single
            // client request. This is a measure of how long this specific individual read took, not total time since

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Re-read the row to determine the actual outcome before retrying (LWT timeouts mean unknown, not failure)
  2. Reduce contention on the partition: shard hot keys, add jitter/backoff to retries, or redesign to avoid CAS on a single hot row
  3. Use the driver's LWT contention-retry policy or application-level exponential backoff
  4. For multi-key/high-contention workloads, consider Accord transactions instead of Paxos LWT

Example fix

// before: blind retry on LWT timeout
} catch (WriteTimeoutException e) { retryInsert(row); }
// after: verify outcome first
} catch (WriteTimeoutException e) {
    Row r = readRow(key); // serial read to learn actual state
    if (!applied(r)) retryInsertWithBackoff(row);
}
Defensive patterns

Strategy: retry

Validate before calling

// minimize contention before issuing CAS
long waits = session.execute("SELECT writetime(v) FROM t WHERE k=?", key).one() != null ? 1 : 0; // detect hot key usage
// add jittered backoff between attempts

Try / catch

try { rs = session.execute(cas); }
catch (WriteTimeoutException e) {
    // outcome unknown: read current state to decide, then retry with backoff
    if (!wasApplied(readCurrentState(key))) retryWithJitteredBackoff();
}

Prevention

When it happens

Trigger: Concurrent LWT/transactional writes to the same partition: our proposal was superseded or uncertain (MAYBE) after the propose phase, so the coordinator throws MaybeFailure which is delivered to the client as a timeout with unknown outcome.

Common situations: Hot-row contention where multiple clients CAS the same partition concurrently; retried LWTs colliding with fresh attempts; applications not handling 'operation timed out — unknown result' after LWTs; heavy contention causing repeated timeouts on the same key.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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