← Back to PRs

#23309: fix: remove 30-minute timeout for background exec sessions

by vksvikas open 2026-02-22 06:01 View on GitHub →
agents size: XS
## Problem Background exec sessions (started with `background: true` or `yieldMs`) are silently killed after exactly 30 minutes. Users experience this as mysterious `Exec failed (session-id, signal SIGTERM)` messages with no clear cause. **Real-world impact:** Any background task running longer than 30 minutes is killed, including: - Batch audio transcription (Whisper processing 930+ files) - Continuous monitoring/polling loops (IoT device tracking, Tesla location polling) - Long-running data processing pipelines Users must resort to `nohup` workarounds, which lose all `process` tool integration (log, poll, kill). Fixes #23303 ## Root Cause The `defaultTimeoutSec = 1800` (30 minutes) in `createExecTool` is applied to **all** exec sessions, including background ones. This timeout is passed to the process supervisor, which fires an `overall-timeout` cancellation via `adapter.kill("SIGKILL")` after 30 minutes, regardless of whether the session was explicitly backgrounded. This is distinct from context compaction (which is often what users are doing when they notice the kills), though compaction can also terminate sessions through separate mechanisms. ## Fix **2 files changed, 16 insertions, 4 deletions** — minimal and surgical. ### `src/agents/bash-tools.exec.ts` - When a session will run in the background (`background: true` or `yieldMs`) AND no explicit `timeout` parameter was provided: skip the supervisor timeout entirely (`null`) - When an explicit `timeout` is provided: always respect it (unchanged) - For synchronous foreground exec: keep the 30-minute safety default (unchanged) ### `src/agents/bash-tools.exec-runtime.ts` - Widen `timeoutSec` type from `number` to `number | null` to support no-timeout background sessions - The existing `typeof opts.timeoutSec === "number" && opts.timeoutSec > 0` guard already handles `null` correctly (produces `timeoutMs = undefined`, so the supervisor never sets a kill timer) - Guard the timeout error message against `null` ## Behavior Matrix | Scenario | Before | After | |----------|--------|-------| | Foreground exec, no timeout | 30 min timeout ✓ | 30 min timeout ✓ (unchanged) | | Foreground exec, explicit timeout | User timeout ✓ | User timeout ✓ (unchanged) | | Background exec, no timeout | **30 min timeout (bug)** | **No timeout ✓ (fixed)** | | Background exec, explicit timeout | User timeout ✓ | User timeout ✓ (unchanged) | ## Related Issues - #23303 — Issue report with detailed reproduction steps - #20436 — Session context lost after agent run timeout (related lifecycle issue) - #18237 — Feature Request: Async exec callback (related long-running process management) ## Testing This was discovered and verified through real-world usage: 1. Launched Whisper batch transcription (930 audio files, ~20 min job) — killed at exactly 30 min, 3 separate times 2. Launched Tesla location polling loop (every 5 min) — killed at exactly 30 min, repeatedly 3. After applying this fix concept (using `nohup` to bypass the supervisor timeout), both processes completed successfully The fix preserves all existing timeout behavior for foreground sessions and explicit user timeouts. <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR fixes a critical bug where background exec sessions were silently killed after 30 minutes due to a hardcoded default timeout. The fix correctly distinguishes between foreground and background sessions, removing the timeout for background sessions unless explicitly set by the user. **Key changes:** - `bash-tools.exec.ts`: Updated timeout logic to skip the supervisor timeout (`null`) for background sessions without an explicit user-provided timeout - `bash-tools.exec-runtime.ts`: Widened `timeoutSec` type from `number` to `number | null` and added null guard for timeout error message **Analysis:** The logic correctly handles all cases: - Foreground sessions maintain the 30-minute safety default - Background sessions (via `background: true` or `yieldMs`) run without timeout when no explicit timeout is provided - Explicit user timeouts are always respected regardless of session type - When backgrounding is disabled (`allowBackground: false`), the default timeout still applies correctly The existing guard `typeof opts.timeoutSec === "number" && opts.timeoutSec > 0` already handles `null` correctly by producing `timeoutMs = undefined`, preventing the supervisor from setting a kill timer. <h3>Confidence Score: 5/5</h3> - This PR is safe to merge - it's a minimal, surgical fix that resolves a critical bug without introducing new risks - The change is well-scoped (2 files, 16 insertions, 4 deletions), preserves all existing behavior for foreground sessions and explicit timeouts, and the logic correctly handles all edge cases. Existing tests already cover background sessions with and without explicit timeouts, confirming the fix works as intended. - No files require special attention <sub>Last reviewed commit: 0e10f53</sub> <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> <!-- /greptile_comment -->

Most Similar PRs