Background Bash tasks get lost/duplicated, turning a simple deploy into 10+ hours of retries
Bug: background Bash tasks get lost/duplicated, turning a simple deploy into 10+ hours of retries
Summary
While running vercel deploy from the Bash tool during a long session, the agent (and I, following its lead) lost track of background task IDs repeatedly: each run_in_background/auto-backgrounded invocation got a new task ID, older ones were abandoned without checking their final state, and until-loop "wait" commands used to poll a task's output file were themselves auto-backgrounded into yet another task ID — creating a chain of orphaned background processes with no single source of truth for "did the deploy finish?".
Combined with transient network errors from the sandbox reaching the Vercel API (EADDRNOTAVAIL, ETIMEDOUT, Not authorized — all on simple status-polling GETs, not on the actual build), a deploy that should take ~2 minutes stretched across 10+ hours and several separate check-ins, because there was no reliable way to answer "is anything still running, and what's its real state?"
Steps to reproduce
- In a long-running session, invoke a Bash command expected to take a while (e.g.
vercel deploy --yes). - Observe the harness auto-backgrounds it even without
run_in_background: true, returning a task ID + output file path. - Try to wait for it with
cat <output-file>immediately — empty (not flushed yet). - Try
sleep N; cat <output-file>— blocked by the harness's anti-sleep-polling guard, which suggests wrapping inuntil ... ; do sleep 2; done. - Run that
untilloop — it ALSO gets auto-backgrounded into a new task ID, separate from the original deploy's task ID. - Now there are two background task IDs in flight for what is conceptually one operation; a
task-notificationeventually arrives for one of them, but the original deploy task's own completion notification can arrive separately (or the loop's completion notification is mistaken for the deploy's). - Repeat under time pressure (retrying after each transient network failure) → task IDs accumulate, some abandoned, and it becomes unclear which background process (if any) is still consuming the terminal/network.
What I expected
- A single, clearly-surfaced way to say "block here until this specific background task finishes" without the wait mechanism itself spawning another background task.
- Or:
run_in_background: false(explicit foreground) actually running in the foreground even for long-duration commands, instead of being silently promoted to background.
What happened instead
- Foreground Bash calls with generous timeouts were still auto-backgrounded.
- The recommended
until-loop wait pattern is itself subject to the same auto-backgrounding, defeating its purpose as a "wait synchronously" idiom. - Net effect: several redundant
vercel deployinvocations were fired across the session (because prior ones' status was unclear), each hitting fresh transient network errors, stretching what should have been a 2-minute operation across a 10+ hour, multi-check-in ordeal.
Environment
- Claude Code (Desktop), version at time of incident: 2.1.209 (session pre-dated an in-session
claude updateto 2.1.212) - macOS, native install
- Bash tool with
run_in_backgroundsupport
Suggested fix
- Either: never auto-background a command whose caller passed
run_in_background: false/omitted it with a boundedtimeout, regardless of estimated duration. - Or: give the Bash tool a first-class "wait for task <id>" primitive that blocks the CURRENT tool call without itself becoming a new background task — so polling loops don't fork into parallel, harder-to-track background chains.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗