[BUG] Session Stops Silently Mid-Turn with `stop_reason: null`

Resolved 💬 4 comments Opened Jan 23, 2026 by coygeek Closed Mar 14, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Claude Code session stopped silently mid-turn without completing its response. The model was actively working on a task (debugging a failed crontab command), produced a thinking block ("Something failed. Let me debug this step by step."), but then stopped without outputting any tool calls, text, or error messages.

The session transcript shows:

  1. All 34 assistant entries have stop_reason: null - even responses that appear complete. This is abnormal; completed responses should have stop_reason: "end_turn" or "tool_use".
  2. The truncated response (entry 66) contains only a single thinking block with output_tokens: 1
  3. Stop hooks ran as if the turn was complete (stop_hook_summary recorded)
  4. User experienced 22 seconds of silence before manually intervening

What Should Happen?

  1. After thinking "Something failed. Let me debug this step by step.", Claude should have continued with tool calls to actually debug the issue
  2. If the API response was incomplete or interrupted, Claude Code should show an error or retry
  3. stop_reason should reflect the actual completion state (end_turn, tool_use, max_tokens, etc.) - not null on every response

Error Messages/Logs

No error messages were displayed. The session simply stopped without any indication.

**Session transcript analysis (via JQ queries on session JSONL):**


# Entry 66 - The truncated response
{
  "type": "assistant",
  "ts": "2026-01-23T02:31:56.013Z",
  "model": "claude-opus-4-5-20251101",
  "stop_reason": null,
  "stop_sequence": null,
  "usage": {
    "input_tokens": 8,
    "output_tokens": 1,
    "cache_read_input_tokens": 54753
  },
  "content_count": 1,
  "content_types": ["thinking"]
}

# Content was just:
[{"type": "thinking", "thinking": "Something failed. Let me debug this step by step."}]

# No tool_use or text blocks followed - response was truncated


**Stop hook summary (ran as if turn was complete):**

{
  "subtype": "stop_hook_summary",
  "hookCount": 3,
  "stopReason": "",
  "preventedContinuation": false
}

Steps to Reproduce

The exact trigger is unclear, but based on analysis:

  1. Start a Claude Code session with Opus 4.5
  2. Have Claude execute a multi-step task with bypassPermissions mode
  3. During the task, have a tool return an error (e.g., bash command exits with code 1)
  4. Observe if the response stream completes properly after Claude's thinking block

Session context that may be relevant:

  • Permission mode: bypassPermissions
  • Working in a local project directory
  • Task: Installing a crontab entry (Phase 2 of a 4-phase plan)
  • Trigger: Bash command crontab -l | ... returned exit code 1

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

2.1.17

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

Session Details

| Field | Value |
|-------|-------|
| Session ID | 2de75cd5-945d-4367-a889-b81354e91a00 |
| Session Path | ~/.claude/projects/<project>/2de75cd5-945d-4367-a889-b81354e91a00.jsonl |
| Duration | ~2 minutes (02:30:36 - 02:32:23 UTC) |
| Total Entries | 238 |
| Assistant Entries | 34 (all have stop_reason: null) |
| Errors | 3 (2x "Exit code 1", 1x "Hook PreToolUse:Bash denied") |

Key Observations

  1. stop_reason: null on ALL responses: Every assistant entry in the session has stop_reason: null. This suggests Claude Code may not be capturing the final streaming chunk's stop_reason correctly.
  1. Low output token counts: Output tokens range from 1-5 across all responses, suggesting these are streaming progress entries rather than complete responses.
  1. Response truncation pattern:
  • Tool result received (exit code 1)
  • Claude produces thinking block only
  • No follow-up action
  • Hooks run as if turn complete
  • Silence
  1. Timeline of the bug:

``
02:31:53.xxx - Bash tool_use executed
02:31:53.xxx - Tool result: "Exit code 1" (is_error: true)
02:31:56.013 - Thinking: "Something failed. Let me debug..."
02:31:56.648 - stop_hook_summary runs (stopReason: "")
[22 seconds of silence]
02:32:18.xxx - User intervenes: "what is your session id"
``

Hypothesis

Claude Code appears to treat streaming responses as complete before the actual stop_reason is received. When a response contains only a thinking block (possibly due to API stream interruption), Claude Code runs stop hooks and waits for user input instead of:

  1. Recognizing the response is incomplete
  2. Retrying or showing an error
  3. Properly capturing the final stop_reason

JQ Queries Used for Analysis

SESSION_FILE="/path/to/session.jsonl"

# Check stop_reason distribution
jq -s '[.[] | select(.type == "assistant") | .message.stop_reason] | group_by(.) | map({reason: (.[0] // "null"), count: length})[]' "$SESSION_FILE"

# Find truncated entry
sed -n '66p' "$SESSION_FILE" | jq '.message'

# Verify all responses have stop_reason: null
jq -c 'select(.type == "assistant") | {ts: .timestamp[11:19], stop: .message.stop_reason}' "$SESSION_FILE"

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗