Skip to content

fix(agent-backend): keep a bounded stderr tail on failed Agent Turns - #1069

Merged
berenddeboer merged 1 commit into
mainfrom
rfa/berenddeboer-ready-for-agent/1057/wi-01KZZDDXAF9M8P6DV8BT9WMBSX
Aug 14, 2026
Merged

fix(agent-backend): keep a bounded stderr tail on failed Agent Turns#1069
berenddeboer merged 1 commit into
mainfrom
rfa/berenddeboer-ready-for-agent/1057/wi-01KZZDDXAF9M8P6DV8BT9WMBSX

Conversation

@berenddeboer

Copy link
Copy Markdown
Owner

When an Agent Backend CLI died with its only explanation on stderr, the
operator never saw it. The originating case was an expired AWS SSO token:
Claude Code exited non-zero in about two seconds, wrote the credential
error only to stderr, emitted no JSONL result, and never tripped the 60s
startup watchdog. runCliTurn had stderr: "ignore", so the text was
discarded and the Cause chain stopped at a bare AgentBackendExitError.

#1056 already surfaces adapter-parsed reasons. This change is the missing
capture path for text that exists only on stderr (#1057).

What changed

  • Agent Turns pipe stderr and drain it inside the same raced Effect.all
    as stdout and exitCode, so a piped stream is never left undrained.
  • The fold keeps the last 4000 characters (same bound as Install
    Dependencies).
  • On non-zero exit, if the adapter supplied no reason, the tail is
    sanitized (ANSI stripped, token-shaped secrets redacted) and then
    truncated to the last 500 characters as AgentBackendExitError.message.
    An adapter-supplied reason still wins.
  • A CLI that writes only to stderr still hits the startup watchdog.
    Finalize still tree-kills immediately; the fold cannot block that kill.

Verification

  • runCliTurn: stderr-only exit message, adapter precedence, flood plus
    4000-character fold bound, sanitization and a token that straddles the
    500-character cut, finalize timing, stderr-only startup watchdog.
  • Implement: a fake CLI that writes only to stderr shows
    AgentBackendExitError 1 — … in extractCauseChain.
  • agent-backend tests and the Claude, Codex, Grok, and OpenCode adapter
    suites stayed green.

Limitations

Closes #1057

When an Agent Backend CLI died with its only explanation on stderr, the
operator never saw it. The originating case was an expired AWS SSO token:
Claude Code exited non-zero in about two seconds, wrote the credential
error only to stderr, emitted no JSONL `result`, and never tripped the 60s
startup watchdog. `runCliTurn` had `stderr: "ignore"`, so the text was
discarded and the Cause chain stopped at a bare `AgentBackendExitError`.

#1056 already surfaces adapter-parsed reasons. This change is the missing
capture path for text that exists only on stderr (#1057).

**What changed**

- Agent Turns pipe stderr and drain it inside the same raced `Effect.all`
  as stdout and `exitCode`, so a piped stream is never left undrained.
- The fold keeps the last 4000 characters (same bound as Install
  Dependencies).
- On non-zero exit, if the adapter supplied no reason, the tail is
  sanitized (ANSI stripped, token-shaped secrets redacted) and then
  truncated to the last 500 characters as `AgentBackendExitError.message`.
  An adapter-supplied reason still wins.
- A CLI that writes only to stderr still hits the startup watchdog.
  Finalize still tree-kills immediately; the fold cannot block that kill.

**Verification**

- `runCliTurn`: stderr-only exit message, adapter precedence, flood plus
  4000-character fold bound, sanitization and a token that straddles the
  500-character cut, finalize timing, stderr-only startup watchdog.
- Implement: a fake CLI that writes only to stderr shows
  `AgentBackendExitError 1 — …` in `extractCauseChain`.
- `agent-backend` tests and the Claude, Codex, Grok, and OpenCode adapter
  suites stayed green.

**Limitations**

- Silent non-zero exits with empty stderr still have no message (staged
  for #1066).
- Fold-fiber leak is prevented by putting the drain in the race, not by
  an Effect child-fiber assertion (not observable after tree-kill).

Closes #1057
@berenddeboer
berenddeboer marked this pull request as ready for review August 14, 2026 06:27
@berenddeboer
berenddeboer merged commit d34b533 into main Aug 14, 2026
5 checks passed
@berenddeboer
berenddeboer deleted the rfa/berenddeboer-ready-for-agent/1057/wi-01KZZDDXAF9M8P6DV8BT9WMBSX branch August 14, 2026 06:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Capture a bounded stderr tail for Agent Turns

1 participant