#6302: fix: Add timeouts to prevent indefinite hangs (issues #4954, #4956, #5122)
channel: whatsapp-web
gateway
Cluster:
Timeouts and Memory Management Fixes
Adds timeout mechanisms to three critical functions that could hang forever:
## Changes
### 1. waitForWaConnection() (#4956)
- Added 60s timeout (configurable)
- Prevents WhatsApp channel from hanging on connection issues
- Rejects with clear error message on timeout
### 2. readJsonBody() (#5122) - P0 Security
- Added 30s read timeout (configurable)
- Prevents Slowloris DoS attacks on webhook endpoint
- Cleans up request on timeout
### 3. GatewayClient.request() (#4954)
- Added 30s default timeout (configurable via opts.timeoutMs)
- Prevents memory leak in pending Map on unresponsive gateway
- Cleans up pending entry on timeout
## Pattern
All follow the same pattern:
- Add optional timeoutMs parameter with sensible defaults
- Use setTimeout to race against operation
- Clean up resources (pending entries, event listeners) on timeout
- Return clear error messages
## Impact
These fixes prevent resource exhaustion and improve availability when network conditions are poor or gateway is unresponsive.
Closes #4954, closes #4956, closes #5122
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR adds timeout protection to several I/O paths to avoid indefinite hangs: WhatsApp Web connection wait, webhook JSON body reads, and gateway RPC requests. It also includes a small daemon-output hardening change (safe writes for EPIPE/EIO) and launchd plist throttling.
The general direction is solid (timeouts + cleanup), but there are a couple of correctness gaps: the gateway request timeout is not actually configurable per call (despite the PR description) and the timeout handle is stored via an untyped escape hatch, which makes it easy to leak timers (notably when flushing pending requests). The webhook body read timeout is also not cleared on all connection termination paths (e.g. `close`).
<h3>Confidence Score: 3/5</h3>
- This PR is directionally good but has a couple of real correctness/cleanup bugs around timeouts that should be fixed before merge.
- Main risk is in `GatewayClient.request()` where timeouts are implemented via an untyped field and not cleared during bulk rejection; this can keep timers alive and cause late rejects. `readJsonBody()` also doesn’t clear timeout on all termination events.
- src/gateway/client.ts, src/gateway/hooks.ts
<!-- greptile_other_comments_section -->
<sub>(5/5) You can turn off certain types of comments like style [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#7615: fix(gateway): add request timeout to GatewayClient
by alamine42 · 2026-02-03
82.7%
#6466: fix(gateway): add handshake timeout and connection error handling
by jarvis-raven · 2026-02-01
82.2%
#10636: fix: setTimeout integer overflow causing server crash
by devmangel · 2026-02-06
79.1%
#9178: Fix: GatewayClient queueConnect() setTimeout never fires
by vishaltandale00 · 2026-02-04
79.0%
#13055: fix: prevent cron RPC stalls with timeout and caching (#13018)
by trevorgordon981 · 2026-02-10
78.9%
#17678: fix(gateway): expose timeoutMs in readJsonBody to prevent Slowloris...
by mcrolly · 2026-02-16
78.5%
#4653: fix(gateway): improve crash resilience for mDNS and network errors
by AyedAlmudarra · 2026-01-30
78.1%
#13084: fix(daemon): multi-layer defense against zombie gateway processes
by openperf · 2026-02-10
78.1%
#11522: Fix #10904: Add hard timeout to lane tasks to prevent cron wedging
by divol89 · 2026-02-07
77.8%
#12953: fix: defer gateway restart until all replies are sent
by zoskebutler · 2026-02-10
77.4%