concept

Ambiguous Outcome

also called Unknown State, Indeterminate Result

The state a system is in when a call times out - not failure, but unknown - and the design obligation to have somewhere to put it.

timeoutspaymentsmarqetareconciliationstate-machine

A timeout on a write does not mean the write failed. It means you do not know whether it failed. The request may have been lost, or processed and the response lost, or still executing.

Systems that model only success and failure are forced to guess. Guessing about money produces duplicates or losses, and it produces them silently, because both guesses look like a normal outcome.

Why it matters

Ambiguity is the normal case in distributed systems, not the exception, and it becomes a large fraction of outcomes exactly when the system is under stress. A design with no representation for "unknown" therefore has its worst behaviour at its busiest moment.

Implementation patterns

  • Model a pending state explicitly in the state machine, with its own timeout and its own resolution path. Not an error state and not a success state.
  • Resolve it by asking the authority, not by inferring. A status query against the provider using your own reference is definitive; a retry is not.
  • Attach a resolution deadline to every pending record, after which it escalates rather than sitting forever. Ambiguous states that never resolve accumulate into a manual workload.
  • Make the user-facing behaviour explicit. "Processing" is a legitimate thing to show a customer and a far better product than a confident wrong answer in either direction.
  • Reconcile. A daily comparison against the counterparty's record is the only mechanism that closes ambiguities the system could not resolve itself.
  • Never let a circuit breaker convert ambiguity into a plain error. If requests may already have taken effect downstream, opening the breaker must return a state the rest of the system knows how to resolve.

Industry example

Card-processing platforms such as Marqeta face this on every authorisation: a timeout to the network may mean no authorisation, or an authorisation that placed a hold on the cardholder's balance. The correct response is not to retry blindly — that risks a second hold — but to issue a reversal or a status query against the original reference. The reversal path is an architectural component, not an error handler.

The same shape appears wherever an external effect is irreversible: a payout instruction to a bank, a dispatch instruction to a courier, an order sent to an exchange.

Failure scenarios

  • Timeout treated as failure, so the operation is retried and duplicates.
  • Timeout treated as success, so a failed payment is recorded as complete.
  • Pending states with no resolution job, accumulating until someone notices the backlog.
  • Retry used as the resolution mechanism for a non-idempotent external call.
  • No reconciliation, so the ambiguities that the automated paths missed are discovered by a customer.

Trade-offs

Modelling ambiguity properly costs a state machine that is meaningfully more complex, a resolution service, a reconciliation process, and a user experience that must express uncertainty. Teams under delivery pressure routinely skip it and collapse ambiguity into failure, which works until volume rises.

The honest framing is that the complexity is not optional, only deferred. It reappears as a manual operations team reconciling exceptions by hand, which is more expensive than the code would have been and does not scale.

Interview question

"Your call to the payment network times out after eight seconds. Tell me exactly what your system does next, what the customer sees, and how the record is eventually closed. Then tell me what happens if that resolution also times out."