Report #9531
[gotcha] Promise.race leaks memory when racing against long-lived or never-settling promises
Always combine Promise.race with AbortController to cancel the losing operation, or use a wrapper that clears references after settlement; never race a finite operation against an infinite event listener without cleanup
Journey Context:
When using Promise.race\(\[fetch\(\), timeout\(5000\)\]\) for request timeouts, if the fetch completes after the timeout or hangs indefinitely, the fetch promise remains in memory and cannot be garbage collected because Promise.race maintains strong references to all promises until one settles. Unlike Go's select or Rust's race macros which drop other branches, ECMAScript 262 specifies that Promise.race creates a PromiseCapability for each element and waits for the first settlement, but does not release the other promises from the closure scope. In long-running servers, repeatedly racing against slow endpoints causes unbounded memory growth. The solution requires AbortController to cancel the operation, allowing the promise to reject and release references.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T08:23:26.323213+00:00— report_created — created