Bounded by configuration
The Route decides how many upstreams a request may try, so no call walks the whole target list.
RPC retries
Every Route carries an attempt bound. The Gateway combines failure certainty with exact operation semantics to decide when another Endpoint is safe.
A Route sets max_attempts, default 3, between 1 and 10, and the effective limit is the lower of the Route value and the deployment limit. Each attempt goes to a different Endpoint, and a candidate leaves the eligible set once it has been tried, so one request never hits the same upstream twice. A Route accepts up to 100 targets; the attempt bound defines the small subset any single request is allowed to walk through.
The Route decides how many upstreams a request may try, so no call walks the whole target list.
Failover moves across upstreams instead of repeating the request against the one that just failed.
An upstream timeout bounds each attempt individually rather than the request as a whole.
Connection and configuration failures can move any operation to another Endpoint. After an ambiguous timeout or interrupted response, the Gateway replays stateless queries and fixed client-signed broadcasts, while Endpoint-local, side-effecting, and unrecognized operations stop conservatively. JSON-RPC notifications are not replayed after an ambiguous access failure or non-2xx response. Matching is exact and protocol-specific instead of relying on method prefixes or HTTP verbs.
Queries and simulations can continue across Endpoints after an ambiguous upstream failure.
The same client-signed payload can be submitted to another Endpoint within the attempt bound.
Custom and unrecognized operations stop after an ambiguous failure instead of guessing.
Before returning an upstream response the Gateway checks its structure: valid JSON, a matching response id, and exactly one of result and error. A response that fails those checks counts as a failure and can move to the next candidate when the operation can be replayed safely, so a malformed 200 does not reach your application as a success. A well-formed upstream JSON-RPC application error is a different case: it is final and does not trigger failover.
Because each attempt carries its own upstream timeout, the bound limits how many sequential upstream timeouts can contribute to the caller's latency budget; the caller still owns the whole-request deadline. A user-facing read is usually better served by a low bound and a fast failure your application can handle, while a background job can afford to walk further down the target list. Circuit rejections do not consume attempts, so a target that is already known to be failing is skipped without spending part of the budget.
Attempts run back to back. The Gateway does not wait between them, because a Route-level pause would hold your connection open while your own timeout is running. Gateway-generated rate-limit responses carry a retry hint, and the right place to space requests out is the caller: exponential backoff, random jitter, and a bounded attempt count on your side, on top of the failover the Route already performs.
Next step
Choose the attempt bound that fits your latency budget; the Gateway handles operation-aware failover internally.