Skip to content

sdk/rs: retry classification misses JSON-RPC response errors (Rust parity with #4100) #4101

Description

@nikw9944

Problem

#4100 fixed retry classification for Go, but #4098's core finding — Go and Rust disagree on what's retryable — is only half resolved. The Rust SDK behind the doublezero CLI retries transport-kind errors only (ClientErrorKind::Io / Reqwest / Middleware in is_retryable_rpc_error, smartcontract/sdk/rs/src/client.rs) and never retries a decoded JSON-RPC error envelope.

That means the two shapes the 2026-07-28 incident and infra#2100 actually arrived in are still one-shot failures for every Rust CLI read:

Rust rode out 07-28 only because those 503s happened to surface at transport level (Reqwest errors). Had they arrived as decoded envelopes — as they did for Go — every CLI invocation would have failed on the first attempt.

Concrete exposure

The QA payments testnet probe (malbeclabs/infra#2100) shells out to doublezero access-pass get twice per run for DZ-ledger reads. After the doublezero-shreds side adopts #4100, these CLI-mediated reads are the probe's last unretried transient-failure path. Any operator or automation using the CLI against a provider-fronted endpoint has the same exposure.

Ask

Mirror #4100's classification in the Rust SDK's retry predicate:

  • retry envelope codes that are really HTTP statuses (429/500/502/503/504) and the provider "busy / retry later" codes (-32005, -32004, -32003, -32429)
  • retry transient message wording (service unavailable, too many requests, bad gateway, gateway timeout) when no recognizable code is set
  • keep onchain/request-level rejections (-32002 preflight failures, -32602, -32601) non-retryable
  • keep send_transaction never retried on ambiguous failures (the same double-submit reasoning as tools/solana: fix JSON-RPC retry classification and consolidate RPC construction #4100)

crates/shred-oracle/src/retry.rs already has a transient-error classifier and backon policies for the shreds repo's Rust side — worth aligning with (or sharing, per #4098's open design question about where common retry code should live) rather than growing a third opinion on retryability.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions