[BUG] stream-json: result event omits the `result` field entirely after a control_request interrupt

Status Open
Reported on v2.1.273
Maintainer reply None cached
Activity 0 comments · opened Sep 16, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet (nearest: #86001 and #88608 cover interrupt semantics; #78686 covers .result content truncation; none cover the key being absent)
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

What's Wrong?

In a --input-format stream-json --output-format stream-json session, interrupting a running Bash tool with a control_request produces a terminal type: result event that has no result key at all. Every other terminal result event carries a string result. A consumer that treats event.result as always-present throws on an otherwise ordinary terminal event, and nothing in the docs says the key can be omitted.

Repro (default login, no API key):

env -u ANTHROPIC_API_KEY claude -p \
  --input-format stream-json --output-format stream-json --verbose \
  --model sonnet --permission-mode acceptEdits --permission-prompts none \
  --allowedTools 'Bash(sleep *)'

stdin, three lines (the third sent while the sleep is running):

{"type":"user","message":{"role":"user","content":[{"type":"text","text":"Reply with exactly: probe-1"}]}}
{"type":"user","message":{"role":"user","content":[{"type":"text","text":"Run Bash sleep 5, then reply FINAL"}]}}
{"type":"control_request","request":{"subtype":"interrupt","request_id":"wh-int-1"}}

What Should Happen?

A stable result-event schema across all terminal events. Any of these would do:

  • emit result: "" (or result: null) on interrupted turns; or
  • document that interrupted result events omit result, and add an explicit discriminator clients can branch on (interrupted: true or terminal_reason: "interrupted") instead of probing for key presence.

Error Messages/Logs

# first turn: result present
{"type":"result","subtype":"success","is_error":false,"terminal_reason":"completed","stop_reason":"end_turn","num_turns":1,"result_index":0,"result":"probe-1"}

# interrupt acknowledged
{"type":"control_response","response":{"subtype":"success","request_id":"wh-int-1","response":{"still_queued":[]}}}
{"type":"user","content":[{"type":"text","text":"[Request interrupted by user for tool use]"}]}

# terminal event for the interrupted turn: no "result" key
{"type":"result","subtype":"error_during_execution","is_error":true,"terminal_reason":"aborted_tools","stop_reason":"tool_use","num_turns":3,"result_index":4,"errors":["[ede_diagnostic] result_type=user last_content_type=n/a stop_reason=tool_use"]}

Environment

  • Claude Code 2.1.273 (reproduced), macOS 15
  • Model: sonnet
  • Consumer: a stream-json driver for long-running headless sessions (we now guard for the missing key; filing so the shape is documented or made stable)

View original on GitHub ↗