-
Notifications
You must be signed in to change notification settings - Fork 540
Description
When using client.messages.stream() with tools, if the model emits malformed JSON during an input_json_delta
event, the user gets a raw internal parser error with no context:
ValueError: expected ident at line 1 column 11
The beta path (_beta_messages.py) already wraps the same call with a clear, actionable message. The non-beta path
(_messages.py) is simply missing the same try-except.
Impact
Every user of client.messages.stream() with tool calling is affected. When this triggers, there is no indication
that the error came from tool input JSON parsing, no mention of what JSON was received, and no guidance on what to do.
It looks like an SDK crash.
Confirmed with real API call (anthropic==0.86.0)
I made a real streaming tool call to claude-haiku-4-5, captured the response, then replayed the events
through accumulate_event with a corrupted JSON delta to trigger the error path in both the non-beta and beta
accumulators.
Normal streaming tool call works fine:
STEP 1: Real API streaming tool call (claude-haiku-4-5)
received: message_start
received: content_block_start
received: content_block_delta
received: input_json
received: content_block_delta
received: input_json
received: content_block_delta
received: input_json
received: content_block_stop
received: message_delta
received: message_stop
Tool called: get_weather({'city': 'Paris'})
Corrupted delta ({"city": INVALID_VALUE}) through both paths:
NON-BETA PATH (accumulate_event from _messages.py):
ValueError: "expected ident at line 1 column 11"
^ Raw jiter error -- no context for the user
BETA PATH (accumulate_event from _beta_messages.py):
ValueError: "Unable to parse tool parameter JSON from model.
Please retry your request or adjust your prompt.
Error: expected ident at line 1 column 11.
JSON: {"city": INVALID_VALUE}"
^ Helpful: tells the user what happened and what to do
Reproduction
from anthropic.types import (
RawMessageStartEvent, RawContentBlockStartEvent, RawContentBlockDeltaEvent,
)
from anthropic.types.message import Message
from anthropic.types.usage import Usage
from anthropic.types.tool_use_block import ToolUseBlock
from anthropic.types.input_json_delta import InputJSONDelta
from anthropic.types.direct_caller import DirectCaller
from anthropic.lib.streaming._messages import accumulate_event
msg = Message(
id="msg_123", type="message", role="assistant", content=[],
model="claude-haiku-4-5", stop_reason=None, stop_sequence=None,
usage=Usage(input_tokens=10, output_tokens=1),
)
snapshot = accumulate_event(
event=RawMessageStartEvent(type="message_start", message=msg),
current_snapshot=None,
)
snapshot = accumulate_event(
event=RawContentBlockStartEvent(
type="content_block_start", index=0,
content_block=ToolUseBlock(
type="tool_use", id="toolu_01", name="get_weather",
input={}, caller=DirectCaller(type="direct"),
),
),
current_snapshot=snapshot,
)
# Malformed JSON delta -- unquoted value
accumulate_event(
event=RawContentBlockDeltaEvent(
type="content_block_delta", index=0,
delta=InputJSONDelta(type="input_json_delta", partial_json='{"city": INVALID_VALUE}'),
),
current_snapshot=snapshot,
)
# Actual: ValueError("expected ident at line 1 column 11")
# Expected: ValueError("Unable to parse tool parameter JSON from model. ...")Root cause
src/anthropic/lib/streaming/_messages.py line 480 -- bare from_json() with no error handling:
if json_buf:
content.input = from_json(json_buf, partial_mode=True)src/anthropic/lib/streaming/_beta_messages.py lines 500-510 -- same call, already wrapped:
if json_buf:
try:
content.input = from_json(json_buf, partial_mode=True)
except ValueError as e:
raise ValueError(
f"Unable to parse tool parameter JSON from model. "
f"Please retry your request or adjust your prompt. "
f"Error: {e}. JSON: {json_buf.decode('utf-8')}"
) from eFix
Wrap the from_json call in _messages.py with the same try-except. 6 lines, zero behavior change for valid JSON.
Environment
anthropicversion:0.86.0- Python:
3.13 - OS: Windows 10