claude-code - 💡(How to fix) Fix [BUG] `claude --print -p` silently exits 143 after ~14 tool round-trips [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#53136Fetched 2026-04-26 05:23:27
View on GitHub
Comments
1
Participants
2
Timeline
6
Reactions
0
Timeline (top)
labeled ×4commented ×1renamed ×1

Error Message

Error Messages/Logs

followed only by clean MCP/LSP teardown — no error, no warn, no

Code Example

### 1a. BSC_exit syscall (ktrace)

Captured via 'ktrace trace -b 1024 --ndjson' on macOS:




args[0] = 143 is the value passed to exit(2). The kernel's proc_exit
W-status confirms (0x8F00 = WIFEXITED true, WEXITSTATUS=143, no signal):




### 1b. CoreAnalytics atexit handler ran (unified log)

Apple's CoreAnalytics framework registers atexit() handlers; they
fire only on voluntary exit() (not on signal-kill):


2026-04-25 13:45:49.070740+1000
2026-04-25 13:45:49.070853+1000
2026-04-25 13:45:49.629451+1000


### 1c. claude's own --debug-file ends mid-stream

Last lines of `--debug all --debug-file ...` before exit. Note that
the very last log line is 'received first chunk' of an API request,
followed only by clean MCP/LSP teardown — no error, no warn, no
stall trigger:


2026-04-25T03:45:42.244Z [DEBUG] [API REQUEST] /v1/messages x-client-request-id=[ID_REDACTED] source=sdk
2026-04-25T03:45:44.690Z [DEBUG] Stream started - received first chunk
2026-04-25T03:45:44.700Z [DEBUG] [API REQUEST] /v1/messages x-client-request-id=[ID_REDACTED] source=sdk
2026-04-25T03:45:47.438Z [DEBUG] Stream started - received first chunk
2026-04-25T03:45:49.071Z [DEBUG] MCP server "pencil": Sending SIGINT to MCP server process
2026-04-25T03:45:49.072Z [DEBUG] LSP server manager shut down successfully
2026-04-25T03:45:49.073Z [DEBUG] Cleaned up session snapshot: /private/var/lib/claude/.claude/shell-snapshots/snapshot-zsh-1777088726273-dx1xg5.sh
2026-04-25T03:45:49.073Z [DEBUG] MCP server "pencil": STDIO connection closed after 33s (cleanly)
2026-04-25T03:45:49.073Z [DEBUG] MCP server "pencil": Cleared connection cache for reconnection
2026-04-25T03:45:49.124Z [DEBUG] MCP server "pencil": MCP server process exited cleanly


## Evidence 2: client-initiated disconnect on 14th /v1/messages

Captured via mitmproxy with HTTPS_PROXY injected post-sudo and
mitmproxy CA installed in system keychain.

Summary of all /v1/messages flows in one --print invocation:


FLOW #1: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  303949 bytes
  response code: 200
  response size: 11247 bytes
FLOW #2: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  309097 bytes
  response code: 200
  response size: 4458 bytes
FLOW #3: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  309600 bytes
  response code: 200
  response size: 5223 bytes
FLOW #4: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  312553 bytes
  response code: 200
  response size: 4329 bytes
FLOW #5: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  317364 bytes
  response code: 200
  response size: 8050 bytes
FLOW #6: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  321382 bytes
  response code: 200
  response size: 4131 bytes
FLOW #7: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  339991 bytes
  response code: 200
  response size: 10382 bytes
FLOW #8: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  355192 bytes
  response code: 200
  response size: 3562 bytes
FLOW #9: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  366285 bytes
  response code: 200
  response size: 30736 bytes
FLOW #10: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  368505 bytes
  response code: 200
  response size: 5534 bytes
FLOW #11: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  369045 bytes
  response code: 200
  response size: 3995 bytes
FLOW #12: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  378110 bytes
  response code: 200
  response size: 4725 bytes
FLOW #13: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  387346 bytes
  response code: 200
  response size: 4389 bytes
FLOW #14: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  389828 bytes
  response code: 200
  response size: 0 bytes


Notable points:

- All 14 requests received HTTP 200 + content-type: text/event-stream
- Flows 1-13: response body is a complete SSE stream ending with
  'event: message_stop'
- Flow 14: response body is 0 bytes. mitmproxy logs the disconnect
  source: '<< 200 OK (content missing) << Client disconnected.'
- Request body grows monotonically (304 KB -> 390 KB) as tool
  results are appended; this is normal conversation growth.

Mitmproxy log line proving the disconnect was client-initiated:


              << 200 OK (content missing)
 << Client disconnected.
--
              << 200 OK (content missing)
 << Client disconnected.
--
[IP]:55371: POST https://http-intake.logs.us5.datadoghq.com/api/v2/logs
 << Client disconnected.


## Evidence 3: stdin invocation does not hit this path

Same prompt content, only difference is delivery channel:


# Failing:
claude --print -p "$(cat prompt.txt)" < /dev/null    # exit 143

# Working:
claude --print < prompt.txt                              # exit 0
# (in test repro: 247s elapsed, did real work, committed)

---

claude --dangerously-skip-permissions --no-session-persistence \
       --model opus --print -p "$(cat large-prompt.txt)" < /dev/null
# elapsed: variable (7-130s observed across runs)
# exit code: 143
# stdout: empty
# stderr: empty
RAW_BUFFERClick to expand / collapse

Preflight Checklist

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

What's Wrong?

Claude Code 2.1.119, --print -p "<prompt>" invocation: after ~14 tool-use round-trips, the CLI disconnects from the in-flight /v1/messages SSE response (HTTP 200, body-not-yet-streamed), runs atexit handlers, and calls exit(143) — emitting no output to stdout/stderr. mitmproxy capture confirms the API server responded with valid headers; the disconnect was client-initiated. Identical prompt fed via stdin (claude --print < prompt.txt) completes successfully. Reproducible on macOS 26.2, Apple Silicon, with prompts that trigger ≥14 tool calls.

Environment

  • macOS: 26.2 arm64
  • Claude Code: 2.1.119 (Claude Code)
  • Claude binary: /opt/homebrew/bin/claude: Mach-O 64-bit executable arm64

Hypothesis

Claude --print mode appears to enforce a turn-count or context-size guard that fires after ~14 tool-use round-trips. When the guard fires, the implementation:

  1. Aborts the in-flight SSE stream by hanging up on api.anthropic.com
  2. Runs registered atexit handlers (MCP SIGINT, LSP shutdown, shell-snapshot cleanup)
  3. Calls exit(143)

The exit code 143 (= 128 + 15) appears to be a deliberate shell-convention signal-to-self indicator; no actual signal is involved. The user-facing symptom is an empty stdout, empty stderr, non-zero exit, with no diagnostic information.

Suggested fixes from a user perspective:

  • Print a diagnostic to stderr when this guard fires (e.g. 'aborted: max tool-use iterations reached for --print mode')
  • Use exit code that distinguishes this from external SIGTERM (e.g. exit 70 / EX_SOFTWARE)
  • Document the cap in --print --help
  • Or: lift the cap, since stdin invocation has no equivalent issue

What Should Happen?

Claude should keep running

Error Messages/Logs

### 1a. BSC_exit syscall (ktrace)

Captured via 'ktrace trace -b 1024 --ndjson' on macOS:




args[0] = 143 is the value passed to exit(2). The kernel's proc_exit
W-status confirms (0x8F00 = WIFEXITED true, WEXITSTATUS=143, no signal):




### 1b. CoreAnalytics atexit handler ran (unified log)

Apple's CoreAnalytics framework registers atexit() handlers; they
fire only on voluntary exit() (not on signal-kill):


2026-04-25 13:45:49.070740+1000
2026-04-25 13:45:49.070853+1000
2026-04-25 13:45:49.629451+1000


### 1c. claude's own --debug-file ends mid-stream

Last lines of `--debug all --debug-file ...` before exit. Note that
the very last log line is 'received first chunk' of an API request,
followed only by clean MCP/LSP teardown — no error, no warn, no
stall trigger:


2026-04-25T03:45:42.244Z [DEBUG] [API REQUEST] /v1/messages x-client-request-id=[ID_REDACTED] source=sdk
2026-04-25T03:45:44.690Z [DEBUG] Stream started - received first chunk
2026-04-25T03:45:44.700Z [DEBUG] [API REQUEST] /v1/messages x-client-request-id=[ID_REDACTED] source=sdk
2026-04-25T03:45:47.438Z [DEBUG] Stream started - received first chunk
2026-04-25T03:45:49.071Z [DEBUG] MCP server "pencil": Sending SIGINT to MCP server process
2026-04-25T03:45:49.072Z [DEBUG] LSP server manager shut down successfully
2026-04-25T03:45:49.073Z [DEBUG] Cleaned up session snapshot: /private/var/lib/claude/.claude/shell-snapshots/snapshot-zsh-1777088726273-dx1xg5.sh
2026-04-25T03:45:49.073Z [DEBUG] MCP server "pencil": STDIO connection closed after 33s (cleanly)
2026-04-25T03:45:49.073Z [DEBUG] MCP server "pencil": Cleared connection cache for reconnection
2026-04-25T03:45:49.124Z [DEBUG] MCP server "pencil": MCP server process exited cleanly


## Evidence 2: client-initiated disconnect on 14th /v1/messages

Captured via mitmproxy with HTTPS_PROXY injected post-sudo and
mitmproxy CA installed in system keychain.

Summary of all /v1/messages flows in one --print invocation:


FLOW #1: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  303949 bytes
  response code: 200
  response size: 11247 bytes
FLOW #2: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  309097 bytes
  response code: 200
  response size: 4458 bytes
FLOW #3: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  309600 bytes
  response code: 200
  response size: 5223 bytes
FLOW #4: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  312553 bytes
  response code: 200
  response size: 4329 bytes
FLOW #5: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  317364 bytes
  response code: 200
  response size: 8050 bytes
FLOW #6: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  321382 bytes
  response code: 200
  response size: 4131 bytes
FLOW #7: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  339991 bytes
  response code: 200
  response size: 10382 bytes
FLOW #8: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  355192 bytes
  response code: 200
  response size: 3562 bytes
FLOW #9: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  366285 bytes
  response code: 200
  response size: 30736 bytes
FLOW #10: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  368505 bytes
  response code: 200
  response size: 5534 bytes
FLOW #11: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  369045 bytes
  response code: 200
  response size: 3995 bytes
FLOW #12: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  378110 bytes
  response code: 200
  response size: 4725 bytes
FLOW #13: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  387346 bytes
  response code: 200
  response size: 4389 bytes
FLOW #14: POST https://api.anthropic.com/v1/messages?beta=true
  request size:  389828 bytes
  response code: 200
  response size: 0 bytes


Notable points:

- All 14 requests received HTTP 200 + content-type: text/event-stream
- Flows 1-13: response body is a complete SSE stream ending with
  'event: message_stop'
- Flow 14: response body is 0 bytes. mitmproxy logs the disconnect
  source: '<< 200 OK (content missing) << Client disconnected.'
- Request body grows monotonically (304 KB -> 390 KB) as tool
  results are appended; this is normal conversation growth.

Mitmproxy log line proving the disconnect was client-initiated:


              << 200 OK (content missing)
 << Client disconnected.
--
              << 200 OK (content missing)
 << Client disconnected.
--
[IP]:55371: POST https://http-intake.logs.us5.datadoghq.com/api/v2/logs
 << Client disconnected.


## Evidence 3: stdin invocation does not hit this path

Same prompt content, only difference is delivery channel:


# Failing:
claude --print -p "$(cat prompt.txt)" < /dev/null    # exit 143

# Working:
claude --print < prompt.txt                              # exit 0
# (in test repro: 247s elapsed, did real work, committed)

Steps to Reproduce

claude --dangerously-skip-permissions --no-session-persistence \
       --model opus --print -p "$(cat large-prompt.txt)" < /dev/null
# elapsed: variable (7-130s observed across runs)
# exit code: 143
# stdout: empty
# stderr: empty

Where 'large-prompt.txt' is a ~210 KB prompt that asks claude to perform code-exploration tool calls (Read, Grep, Bash) on a real codebase. The prompt structure is irrelevant; what matters is that it elicits >=14 tool-use turns in a single --print invocation.

Identical prompt fed via stdin (claude --print < large-prompt.txt) completes successfully (exit 0).

Claude Model

Opus

Is this a regression?

Yes, this worked in a previous version

Last Working Version

No response

Claude Code Version

2.1.119

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Other

Additional Information

No response

extent analysis

TL;DR

The issue can be mitigated by modifying the --print mode to either remove or increase the turn-count or context-size guard that fires after ~14 tool-use round-trips.

Guidance

  • Investigate the --print mode implementation to identify the specific guard that is causing the issue and consider removing or increasing its limit.
  • Modify the exit code to distinguish this scenario from external SIGTERM, for example, by using exit 70 / EX_SOFTWARE.
  • Document the cap in --print --help to inform users of the current limitation.
  • Test the stdin invocation method as a potential workaround, as it does not seem to be affected by the same issue.

Example

No specific code snippet can be provided without access to the Claude Code implementation, but the fix would involve modifying the --print mode logic to handle the turn-count or context-size guard differently.

Notes

The root cause of the issue appears to be a deliberate design choice in the --print mode implementation, and resolving it may require changes to the underlying logic. The stdin invocation method may serve as a temporary workaround for users affected by this issue.

Recommendation

Apply a workaround by using the stdin invocation method (claude --print < prompt.txt) until a permanent fix can be implemented in the --print mode.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING