A never-settling syncState wedges withSyncLock's coalescing forever — a fresh client still joins the corpse
- Dominant language
- TypeScript
- Stars
- 1
- Forks
- 21
- Avg merge
- 12h 14m
- Merged PRs (30d)
- 41
Description
## Symptom
One `syncState()` whose underlying RPC never settles kills sync **permanently for the whole realm**: every later `syncState()` — including from a freshly constructed client — parks instantly without issuing a single network request, and no client-side recovery can release it.
## Why
`withSyncLock` coalesces per `(dbId, methodId)` through a **module-level** `inFlight` map, and the entry is removed only in the promise's `finally`. A sync that never settles (on wasm32 the transport carries no deadline — the wasm `ApiClient` drops its `timeout_ms`) therefore stays in `inFlight` forever, and every subsequent caller joins the corpse's promise. Replacing the client doesn't help: the map (and the `miden-sync-` Web Lock the corpse holds) are shared module state, not client state.
## Evidence (live, on-device — from the 0xMiden/wallet#777 investigation)
- iOS simulator, one sync RPC forced to hang: the wallet evicted its lock holder and built a fresh client; the next tick's `syncState` produced **zero** network traffic and never settled.
- `navigator.locks.query()` at that moment: `held: ["miden-sync-default:exclusive"]`, `pending: []` — held by the abandoned call, and the new caller isn't even queued (it coalesced in `inFlight`).
## Expected
A single stuck call must not be able to wedge sync beyond its own lifetime. The root cure is the transport deadline (miden-client's wasm `ApiClient` ignoring `timeout_ms`); a defensive bound on how long an `inFlight` entry may be joined would additionally keep any future never-settling path from becoming realm-permanent.
## Impact
On mobile (wallet runs the client on the main thread, 3s idle sync) this is the unrecoverable half of wallet#777: after the wedge, the wallet is chain-blind until the app is killed.
Contributor guide
Research direction
Look at the `withSyncLock` function and the module-level `inFlight` map. The bug is in the wasm `ApiClient` transport ignoring the `timeout_ms`. Start by examining the client construction and sync flow to understand where deadlines are set and enforced. The fix involves ensuring the transport respects timeouts and possibly adding a defensive bound to the `inFlight` coalescing. Testing requires simulating a hanging RPC in a wasm environment.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript, wasm
- Domain
- backend, mobile-dev, web-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100