#11874: fix: handle fetch rejections in provider usage withTimeout
stale
Fixes #11786.
## Problem
`withTimeout()` in `provider-usage.shared.ts` races the work promise against a timeout, but only the timeout branch resolves to the fallback value. When the work promise **rejects** (e.g. `TypeError: fetch failed` from network errors), the rejection propagates through `Promise.race`, bypassing the fallback entirely.
This causes `loadProviderUsageSummary` to throw when any provider fetch encounters a network error. Callers catch the exception but lose all provider data, resulting in stale or default UI display (e.g. "100% left" for Gemini quota even when significant quota has been consumed).
**Error from reporter's logs:**
```
warn [openclaw] Non-fatal unhandled rejection (continuing): TypeError: fetch failed
Target URL: https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuota
```
## Root Cause
```typescript
// Before: rejection propagates through Promise.race
return await Promise.race([
work, // ← if this rejects, race rejects too
new Promise<T>((resolve) => {
timeout = setTimeout(() => resolve(fallback), ms);
}),
]);
```
## Fix
```typescript
// After: catch rejection and resolve to fallback
return await Promise.race([
work.catch(() => fallback), // ← network errors now resolve to fallback
new Promise<T>((resolve) => {
timeout = setTimeout(() => resolve(fallback), ms);
}),
]);
```
One-character diff in production code. The `.catch(() => fallback)` ensures network errors, DNS failures, and other fetch exceptions are handled identically to timeouts — graceful fallback across **all** provider usage fetchers (Gemini, Claude, Copilot, Antigravity, Codex, MiniMax, Zai).
## Tests
New test file `provider-usage.shared.test.ts` with 5 cases:
- Normal resolution (work completes before timeout)
- Timeout fallback (work is slow)
- **Rejection fallback with TypeError** (the reported bug)
- Rejection fallback with generic Error
- Rejection fallback with object fallback value
```
✓ src/infra/provider-usage.shared.test.ts (5 tests)
✓ src/infra/provider-usage.test.ts (10 tests)
✓ src/infra/provider-usage.fetch.antigravity.test.ts (18 tests)
```
All 33 existing + new tests pass.
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR updates `withTimeout()` in `src/infra/provider-usage.shared.ts` so that rejections from the raced work promise (e.g. `TypeError: fetch failed`) resolve to the provided fallback instead of propagating through `Promise.race`. This prevents `loadProviderUsageSummary` and other provider-usage fetchers from failing hard on transient network errors and aligns rejection behavior with the existing timeout fallback behavior.
It also adds a focused unit test suite in `src/infra/provider-usage.shared.test.ts` covering success-before-timeout, timeout fallback, and several rejection→fallback scenarios (including non-`Error` fallbacks).
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk.
- Change is narrowly scoped to `withTimeout()` by converting work rejections into fallback resolution, which matches the function’s existing fallback-on-timeout contract. Added tests explicitly cover success, timeout, and multiple rejection variants. No behavioral regressions were found in call sites based on the explored code paths.
- No files require special attention
<!-- greptile_other_comments_section -->
<sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#9407: fix(usage): catch AbortError in withTimeout to prevent CLI crash
by zenchantlive · 2026-02-05
82.0%
#5031: fix: add network connection error codes to failover classifier
by shayan919293 · 2026-01-30
78.0%
#14824: fix: do not trigger provider cooldown on LLM request timeouts
by CyberSinister · 2026-02-12
78.0%
#13626: fix(model): propagate provider model properties in fallback resolution
by mcaxtr · 2026-02-10
77.5%
#16684: fix:(antigravity): align Antigravity OAuth project discovery header...
by vincentkoc · 2026-02-15
77.4%
#10636: fix: setTimeout integer overflow causing server crash
by devmangel · 2026-02-06
77.2%
#23816: fix(agents): model fallback skipped during session overrides and pr...
by ramezgaberiel · 2026-02-22
77.0%
#5630: refactor: extract unified withTimeout utility
by lailoo · 2026-01-31
76.9%
#14914: fix: resolve actual failure reason for cooldown-skipped providers
by mcaxtr · 2026-02-12
76.9%
#14574: fix: gentler rate-limit cooldown backoff + clear stale cooldowns on...
by JamesEBall · 2026-02-12
76.9%