Workflow: transient "Connection closed mid-response" in one agent aborts the whole run and discards all completed work
Workflow: a transient "Connection closed mid-response" in one agent aborts the entire run and discards all completed work
Product: Claude Code, version 2.1.197 (harness claude-code_2-1-197_harness)
Platform: Linux, CLI entrypoint
Feature: the Workflow tool (multi-agent background orchestration)
Summary
A single transient API/network error in one workflow agent() call (API Error: Connection) caused the call to resolve to
closed mid-responsenull, which then crashed the whole
workflow with an unrelated-looking TypeError, discarding a run that had already completed
its audit and synthesis phases and was ~7 agents / ~1M tokens deep. A momentary connection
blip should not be terminal, and it certainly should not throw away all the completed work of
a long-running background job.
Observed
A background workflow (7 agents: 5 audit + 1 synth completed, then the implementation agent)
failed with:
Dynamic workflow "…" failed: Error: null is not an object (evaluating 'impl.classes_foreclosed')
at <anonymous> (workflow.js:222:24)
at processTicksAndRejections (native)
failures: [implement] failed: API Error: Connection closed mid-response. The response above
may be incomplete.
usage: agent_count=7, subagent_tokens=1,016,354, tool_uses=178, duration_ms=2,502,348 (~42 min)
Sequence:
- The
implementagent()hitAPI Error: Connection closed mid-response(a transient
network error).
- That
agent()call resolved tonull(consistent with the documented behavior that
agent() returns null when "the subagent dies on a terminal API error after retries").
- The orchestration then dereferenced the null result (
impl.classes_foreclosed) and the
whole workflow aborted with a TypeError.
- All completed work for the run was discarded; the implementation agent had also written
~real edits to the working tree over 178 tool-uses, which were left uncommitted and
unattributed to the run.
Root cause (two layers)
- A transient
Connection closed mid-responseis treated as terminal. A mid-response
connection drop is exactly the class of error that should be retried transparently; instead
it exhausted (or bypassed) retries and returned null.
- A single agent's
nullresult is unrecoverable and fatal to the run. There is no
preservation of the already-completed agents' results (audit + synth here), so the entire
multi-hour run is lost to one agent's blip.
Expected
- Transient API/network errors (
Connection closed mid-response, and similar) inside a
workflow agent() should be retried transparently before the call is allowed to fail.
- When an agent does ultimately fail, the run should not lose the results of agents that
already completed. The orchestrator should be able to salvage/continue (e.g., the failed
agent() returns null and the workflow retains cached results for a clean resume from
the failed phase — not from phase 1).
- A resume of a run that died this way should re-enter at the failed phase using the cached
completed agents, rather than restarting from the beginning.
Impact
- ~42 minutes and ~1,000,000 tokens of completed multi-agent work discarded by a momentary
network drop.
- This is the third distinct way we have observed a workflow discard completed work on a
single-agent hiccup, all sharing one root pattern — *no partial-result preservation; one
agent's failure = whole-run loss*:
- an interrupted background run cannot be resumed and restarts from phase 1
(resumeFromRunId is same-session-only and only fully-returned agents checkpoint);
StructuredOutput retry cap (5) exceededfails the whole run because an agent could not
format its final report;
- this one — a transient connection drop returns
nulland the run aborts.
Suggested fixes
- Retry transient/network
agent()errors (connection reset/closed mid-response, 5xx,
timeouts) transparently with backoff before surfacing failure.
- On unrecoverable single-agent failure, return a structured result that includes what the
agent did (and, ideally, preserve/report its side effects), rather than null, so scripts
can branch instead of null-dereferencing.
- Persist per-phase checkpoints so a run that dies in phase N resumes at phase N (cross-session
if the journal exists on disk), instead of re-running completed phases.
Reproduction notes / evidence
- Not deterministically reproducible (depends on a transient network drop mid-agent), but
triggered reliably by any Connection closed mid-response during a workflow agent() call.
- Run id
wf_40350274-0a4; full run journal and sub-agent transcripts are on disk under
~/.claude/projects/<slug>/<session>/subagents/workflows/<run-id>/ and can be shared.