fix(desktop): solve #5699 — retry transient terminal-create network failures
Root cause
The terminal-create path (useV2TerminalLauncher.create) calls
trpcClient.terminal.createSession.mutate(...) directly. That vanilla tRPC
mutation has no retry (React Query's retry config only covers queries), so a
single transient connection-level failure — the local host-service momentarily
unreachable because it's busy under load, mid-restart, or its dynamic loopback
port just rotated — rejects with TypeError: Failed to fetch. useV2PresetExecution
catches it and shows the reported toast:
Failed to run preset — Failed to fetch (127.0.0.1:48135)
This matches the report: it happens after extended usage, is intermittent, and
"resolved by restarting" (which respawns host-service on a fresh port). The
request never reaches host-service, so nothing actually ran.
The fix
terminal.createSession is documented and implemented as idempotent on
host-service (existing in-memory session → no-op; adopt a surviving daemon PTY;
otherwise spawn). Because a connection-level fetch failure never lands on the
server, retrying it can't create a duplicate session. The new
withNetworkRetry helper wraps the create call and retries only transient
network errors (Failed to fetch / Load failed / ECONNREFUSED / …) with a
short linear backoff. Server-side errors (validation, INTERNAL_SERVER_ERROR)
still fail fast.
Tests
create-session-retry.test.ts:
- Reproduction — with no retry (
attempts: 1), a singleFailed to fetch
aborts the call, exactly as the code behaves today. - Resolution — a transient failure followed by success now recovers.
- Guards: gives up after exhausting attempts; never retries non-network errors;
isTransientNetworkErrorclassification.
Notes / scope
This hardens the renderer→host-service create path, which directly produces the
reported symptom. The underlying flakiness may have additional contributors in
the host-service/daemon lifecycle (e.g. adopted-daemon liveness, port rotation
windows) that are environment-dependent and not deterministically reproducible
in a unit test — hence draft, so a maintainer can confirm this addresses the
field reports before merge.
Closes #5699
Summary by cubic
Retries transient network failures when creating terminal sessions to prevent the “Failed to run preset — Failed to fetch (127.0.0.1:)” toast. Improves reliability of preset runs and new terminal actions, addressing #5699.
- Bug Fixes
- Added
withNetworkRetrywith short linear backoff; retries only transient network errors (e.g., “Failed to fetch”, “Load failed”,ECONNREFUSED); server errors fail fast. - Wrapped
trpcClient.terminal.createSession.mutateinuseV2TerminalLauncherwith the retry helper; safe due to idempotent create semantics. - Tests cover reproduction without retry, recovery after a transient blip, giving up after attempts, and error classification.
- Added