Claude Code CLI: --max-budget-usd
Claude Code CLI: --max-budget-usd tripping inside a subagent hangs the query (no ResultMessage)
Component: Claude Code CLI as run by the Python Agent SDK (claude-agent-sdk 0.2.134, bundled CLI
2.1.226; reproduced again on CLI 2.1.259 bundled in SDK 0.2.152, Linux aarch64).
Platforms seen: Windows 11 x64 (laptop), Raspberry Pi OS 64-bit / Debian Trixie (Pi 5).
Severity: a headless caller never gets a result; only its own wall clock ends the turn.
Summary
When max_budget_usd (CLI --max-budget-usd) is exceeded while a subagent spawned by the Agent tool is
running, the parent query emits no ResultMessage (neither success nor error_max_budget_usd). The
subagent's own transcript shows it finished its work, but the parent never receives the Agent tool_result and
the stream stays open until the client gives up. When the same cap trips on the main thread the query ends
normally with subtype: error_max_budget_usd.
Environment
- Python 3.14,
claude-agent-sdk==0.2.134, its bundledclaude2.1.226 (_cli_version.py); alsoclaude-agent-sdk==0.2.152with bundled 2.1.259 on a Raspberry Pi 5. - Auth:
claude setup-token(OAuth), not an API key. - Options that matter:
permission_mode="bypassPermissions",agents={...}with twoAgentDefinitions (tools=[...],disallowedTools=[...],model="haiku"in the repro),tools=["Read", "WebSearch", "Agent"],strict_mcp_config=True, two in-process SDK MCP servers, a PreToolUse hook that allows every call in the repro,max_budget_usd=0.02,max_turns=40,setting_sources=[],env={"CLAUDE_CODE_DISABLE_AUTO_MEMORY": "1"}.
Minimal repro (what the 18 Sep 2026 smoke did)
- Define one agent, e.g.
worker, with a system prompt that tells it to call an MCP tool a few times before answering, and a parent system prompt that says: delegate any question about X toworkerthrough the Agent tool and paste its answer. - Set
max_budget_usd=0.02on the parent options (small enough that the cap trips during the subagent's second or third model call; the parent had spent US$0.0097 at the moment it delegated in our run). async for message in query(prompt="<a question about X that needs 3 tool calls>", options=options).- Observe the stream:
SystemMessages, the parent'sAssistantMessagewith the Agenttool_use,TaskStartedMessage, the subagent's tool calls (the PreToolUse hook fires for each withagent_type="worker"), then nothing. NoTaskNotificationMessagecarrying the result, no parentAssistantMessage, noResultMessage. Our client waited 300 s (laptop) and 420 s (Pi) before cancelling. - Control: the same prompt with
max_budget_usd=Nonecompletes in ~20 s withResultMessage(subtype="success"); the same cap on a prompt the parent answers without delegating ends withResultMessage(subtype="error_max_budget_usd")as documented.
Observed on both CLIs above, three runs each. The subagent's transcript under ~/.claude/projects/<slug>/
ends with its final answer, so the work completed; the loss is in handing the result (or the budget error) back
to the parent when the budget check fires inside the subagent's loop.
Not deterministic: a fourth run on CLI 2.1.259 (19 Sep 2026, 01:00 WIB, same max_budget_usd=0.02, the
subagent's one tool call finished in a few seconds) came back after 24 s with the partial reply and a
ResultError raised by the SDK instead of an error_max_budget_usd ResultMessage, so the caller's generic
error path ran ("I hit an error part-way through"). The hang appears when the cap trips while the subagent is
mid-loop; when it trips after the subagent has returned, the turn ends, but as a raised error rather than the
documented subtype.
Expected
Either the parent receives the Agent tool_result (or an error tool_result saying the budget was exceeded) and
then a ResultMessage with subtype="error_max_budget_usd", or the query ends immediately with that
ResultMessage. Any terminal message; never an open stream.
Workaround in use
max_budget_usd is left unset when subagents are enabled (TURN_BUDGET_USD=0 in my bot). Bounds that hold:
the caller's own asyncio.wait_for wall clock, max_turns, CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=1 and
CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS=2 in the subprocess env. A related observation from the same
investigation (19 Sep 2026, CLI 2.1.226): AgentDefinition.maxTurns=2 on the subagent did not stop it either;
it ran four tool calls to completion, so per-agent maxTurns is not currently a usable bound from the SDK.
Source: anthropics/claude-agent-sdk-python