Skip to content

fix(ctx_shell): stop reporting a requested background cancel as a tool error - #1248

Open
andig wants to merge 1 commit into
yvgude:mainfrom
andig:fix/1246-background-cancel-not-an-error
Open

fix(ctx_shell): stop reporting a requested background cancel as a tool error#1248
andig wants to merge 1 commit into
yvgude:mainfrom
andig:fix/1246-background-cancel-not-an-error

Conversation

@andig

@andig andig commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Cancelling a background ctx_shell job answered with the same [background:<id> running] string that background_action: "status" returns, so the cancel was indistinguishable from a no-op poll — and the obvious follow-up (cancel again) surfaced the process's own SIGINT exit as the tool's exit code. In Claude Code that fires the PostToolUseFailure hook and instructs the agent to fix a non-problem.

Changes

  • First cancel is acknowledged. A cancel on a running job now returns [background:<id> cancel requested — job is stopping; poll status for the final output] instead of the status wording.
  • A completed cancel is not a tool error. The terminal state reports as [background:<id> cancelled]\n<output>\n[cancelled: <id>, exit 130] with exit 0, so exit 130 stays visible as data without tripping the failure hook.
  • Cancel is idempotent. Cancelling an already-cancelled, already-finished (any exit code) or already-pruned job is equally non-error. A status poll keeps its previous exit-code semantics.
  • ERROR: command cancelled in the captured output becomes [cancelled: command stopped on request] — the flag is only ever set by an explicit cancel, so the ERROR: prefix was wrong at the source too.

The formatting moved into format_background_state(id, is_cancel, state); no tool-schema or description change.

Testing

  • New tools::registered::ctx_shell::tests::cancel_is_acknowledged_and_never_reports_a_failure covers the ack wording, exit 0 on the cancelled state, idempotence over Completed/None, and that a status poll is unaffected.
  • cargo test --lib ctx_shell:: (58 passed), cargo test --lib background_shell:: (9 passed), cargo clippy --all-targets clean.

Fixes #1246

🤖 Generated with Claude Code

…l error

Cancelling a background job answered with the same '[background:<id>
running]' string a status poll returns, so the cancel looked like a no-op
and the natural next move was to cancel again. That second call then
surfaced the process's own SIGINT exit as the tool's exit code, tripping
the client's failure hook and instructing the agent to fix something it
had deliberately done.

A cancel now acknowledges itself distinctly, reports the terminal state
as data ('[cancelled: <id>, exit 130]') with exit 0, and is idempotent:
cancelling an already-cancelled, already-finished or already-pruned job
is equally benign. The cancelled marker in the captured output loses its
'ERROR:' prefix for the same reason - a caller-requested stop is not a
failure.

Fixes yvgude#1246

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

ctx_shell: background cancel looks like a no-op, then reports success as a tool error (exit 130)

1 participant