Skip to content

client: surface redirect-cap exhaustion as a typed ClientError, not a synthetic tonic::Status #626

Description

@SebastianThiebaud

The client's redirect caps are surfaced to callers as synthetic tonic::Status::failed_precondition values. When the per-pass cap (MAX_LEADER_REDIRECTS) or absolute cap (MAX_TOTAL_LEADER_REDIRECTS) is hit, the client writes a fabricated failed_precondition("leader-hint redirect cap ... reached") into both election_signal and last_err (retry.rs:277-278/:676-677/:943-944). If that synthetic status ends up being the surfaced error, the caller receives a client-manufactured FAILED_PRECONDITION whose message describes an internal client limit rather than any server-reported state. This is an error-laundering smell: a client-internal cap is dressed up as a gRPC-shaped server precondition, which a caller inspecting status.code()/status.message() for retry/alerting decisions cannot distinguish from a real precondition failure.

Scope

  • crates/tsoracle-client/src/retry.rs:277-278,676-677,943-944 (and the absolute-cap sites) — introduce a dedicated ClientError variant (e.g. RedirectCapExceeded { scope: PerPass | Absolute }) for the cap conditions instead of synthesizing a tonic::Status.
  • Keep "the cluster told us X" (real tonic::Status) cleanly separated from "the client gave up after N pivots" in surface_error's precedence.

Exit criteria

  • cargo test -p tsoracle-client passes (redirect-cap behavior unchanged; the new variant is asserted in the cap tests).
  • A caller can distinguish a client-internal cap from a server-reported FAILED_PRECONDITION.

Explicit non-goal

Changing the cap values or when the client gives up — only how that condition is represented to the caller. Folds naturally into the retry-loop de-duplication issue.

Parent:

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    error handlingImprovements to how failures are represented and propagatedrefactorImprovements to structure, readability, or maintainability while preserving external behavior

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions