#12477: fix(agents): prevent TimeoutOverflowWarning when timeout is disabled
gateway
agents
stale
Cluster:
Timeouts and Memory Management Fixes
## Summary
`resolveAgentTimeoutMs` uses a 30-day constant (`2,592,000,000 ms`) to represent "no timeout" when the caller sets `timeout: 0`. This exceeds Node's 32-bit signed integer limit for `setTimeout` (`2,147,483,647 ms`), causing Node to emit `TimeoutOverflowWarning` and clamp the value to `1 ms` — which prematurely kills sub-agents almost immediately instead of letting them run indefinitely.
The fix eliminates the overflowing constant entirely. Instead of scheduling a timer with a huge value, callers skip timer creation when no timeout is requested.
## Changes
- `src/agents/timeout.ts` — return `0` for "no timeout" instead of the overflowing 30-day constant; export a documented `NO_TIMEOUT` sentinel callers can reference
- `src/agents/pi-embedded-runner/run/attempt.ts` — skip the abort timer when `timeoutMs` is `0` instead of passing it to `setTimeout`
- `src/gateway/server-methods/agent-job.ts` — skip the completion timer when `timeoutMs` is `0`
`block-reply-pipeline.ts` already handles `timeoutMs <= 0` correctly (returns the promise directly without a timer).
## Test plan
- `sessions_spawn` with `timeout: 0` no longer emits `TimeoutOverflowWarning` in Node logs
- Sub-agents with no explicit timeout run until completion instead of being killed at 1 ms
- Explicit positive timeouts (e.g. `timeout: 600`) behave exactly as before
- `clearTimeout(undefined)` is a safe no-op in Node, so cleanup paths remain correct
Fixes #12407
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR changes the agent timeout semantics so that an explicit `timeout: 0` no longer maps to a huge “effectively infinite” millisecond value (which overflows Node’s `setTimeout` limit and gets clamped to `1ms`). Instead, `resolveAgentTimeoutMs` returns a `NO_TIMEOUT = 0` sentinel and call sites in the embedded runner and gateway job-waiter skip creating timers when `timeoutMs === 0`.
The overall direction matches the described bug (prevent `TimeoutOverflowWarning` and premature aborts), but there’s one behavior mismatch in the gateway’s `waitForAgentJob` path that currently treats `timeoutMs <= 0` as an immediate timeout response rather than an indefinite wait.
<h3>Confidence Score: 3/5</h3>
- This PR addresses the Node timeout overflow issue but has a semantic regression in the gateway wait path for `timeoutMs=0`.
- Main fix (stop scheduling overflowing timers) is correct in the embedded runner, but `src/gateway/server-methods/agent-job.ts` still returns immediately for `timeoutMs <= 0`, which conflicts with the new `NO_TIMEOUT = 0` sentinel meaning and will cause `agent.wait` to report an immediate timeout when clients pass 0 to mean “no timeout”.
- src/gateway/server-methods/agent-job.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
#9114: Fix: Reduce NO_TIMEOUT_MS to 24 days to avoid Node.js overflow warning
by vishaltandale00 · 2026-02-04
86.0%
#10636: fix: setTimeout integer overflow causing server crash
by devmangel · 2026-02-06
85.4%
#11416: fix: clamp timeout values to avoid 32-bit overflow warning
by seojoonkim · 2026-02-07
83.7%
#22719: fix(agents): make subagent announce timeout configurable (restore 6...
by Valadon · 2026-02-21
79.8%
#17721: fix: abort child run on subagent timeout + retry with backoff + sta...
by IrriVisionTechnologies · 2026-02-16
78.3%
#18432: fix(agents): clear active run state immediately on embedded timeout
by BinHPdev · 2026-02-16
77.3%
#6302: fix: Add timeouts to prevent indefinite hangs (issues #4954, #4956,...
by batumilove · 2026-02-01
77.0%
#6268: fix: add timeout to compaction retry to prevent session lockout
by batumilove · 2026-02-01
76.5%
#19414: fix: respect job timeoutSeconds for stuck runningAtMs detection
by namabile · 2026-02-17
76.2%
#6143: fix(agents): handle AbortError from activeSession.abort() on timeout
by Glucksberg · 2026-02-01
75.8%