opus-4.8 / sonnet-4.6 intermittently omit a required tool-call input field when streaming via native Anthropic /v1/messages #198125
Replies: 3 comments
-
|
💬 Your Product Feedback Has Been Submitted 🎉 Thank you for taking the time to share your insights with us! Your feedback is invaluable as we build a better GitHub experience for all our users. Here's what you can expect moving forward ⏩
Where to look to see what's shipping 👀
What you can do in the meantime 💻
As a member of the GitHub community, your participation is essential. While we can't promise that every suggestion will be implemented, we want to emphasize that your feedback is instrumental in guiding our decisions and priorities. Thank you once again for your contribution to making GitHub even better! We're grateful for your ongoing support and collaboration in shaping the future of our platform. ⭐ |
Beta Was this translation helpful? Give feedback.
-
|
Update — more data, and a second (more diagnostic) failure shape Following up on my own report with a fresh session and full request/response traces. Same tool (AskUserQuestion), same streaming native-Anthropic /v1/messages path, but a distinct corruption morphology that points at the same root cause: the model intermittently mis-serializes the tool input while streaming. Setup: claude-opus-4.8, streamed, relayed through a byte-level passthrough proxy. The proxy does not parse, re-encode, or reassemble content_block_delta — input_json_delta fragments are forwarded verbatim. Non-streaming is unaffected, consistent with before. Frequency this session: 3 of 17 AskUserQuestion calls corrupted (all on opus-4.8). Every other tool-input block in the same capture — several hundred calls across ~30 tools (Bash/Read/Edit/Write/Grep/…) — was well-formed. Only AskUserQuestion, the one tool whose input is a nested array of objects, was hit. Schema: AskUserQuestion.questions is type array. Healthy output (14/17) — questions is an array, CJK as raw UTF-8: Corrupted output (3/17) — the whole array is serialized into a string, and inside that string the model hand-encodes CJK as \uXXXX, with exactly one broken escape per response: Two independent defects, both server-side:
The corruption is inside a single SSE fragment, not a concatenation seam. The on-the-wire input_json_delta that carries it: Signature: all three breaks land at a CJK→ASCII word boundary, immediately before the ASCII token Azure: ┌─────┬───────────────┬───────────────────┐ Net effect for the client (Claude Code here): the outer object parses, fails schema (string ≠ array), and surfaces as "Invalid tool parameters." This is consistent with the original report (intermittent, streaming-only, schema-invalid AskUserQuestion input) and adds a precise trigger: mixed CJK/ASCII content in a nested tool-input field, streamed, occasionally makes the model (a) stringify the nested structure and (b) split a \uXXXX escape at the multibyte→ASCII boundary. The earlier "dropped field" shape and this "stringify + broken escape" shape are two manifestations of the same malformed serialization on the streaming path. |
Beta Was this translation helpful? Give feedback.
-
|
We've managed to consistently reproduce the "Invalid tool parameters" (stringified array / dropped fields) issue with Claude Opus 4.8 when streaming via the Copilot The issue can be observed using a pure HTTP call. The bug triggers intermittently (but very frequently) when the model needs to generate an array of complex objects inside a tool call during a streaming request. Reproduction StepsYou can reproduce this by sending a 1. The curl -X POST https://api.githubcopilot.com/chat/completions \
-H "Authorization: Bearer <YOUR_COPILOT_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-H "Editor-Version: vscode/1.90.0" \
-H "Copilot-Integration-Id: vscode-chat" \
-d '{
"model": "claude-opus-4.8",
"max_tokens": 4096,
"stream": true,
"tool_choice": {"type": "tool", "name": "AskUserQuestion"},
"tools": [{
"name": "AskUserQuestion",
"description": "Ask the user one or more multiple-choice questions.",
"input_schema": {
"type": "object",
"properties": {
"questions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"question": {"type": "string"},
"header": {"type": "string"},
"multiSelect": {"type": "boolean"},
"options": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": {"type": "string"},
"description": {"type": "string"}
}
}
}
},
"required": ["question", "header", "options", "multiSelect"]
}
}
},
"required": ["questions"]
}
}],
"messages": [
{
"role": "user",
"content": "I am choosing a database and a deploy target for a new web app. Ask me two questions to narrow it down, each with 3 options."
}
]
}'(Note: Replace the endpoint with the Anthropic-compatible 2. Expected vs. Actual Observed Output When watching the Buggy SSE Stream Output (Stringified Array): data: {"type": "content_block_delta", "index": 0, "delta": {"type": "input_json_delta", "partial_json": "{\"questions\": \"[{\\\"question\\\":\\\"What kind of data structure best fits your web app's needs?\\\",\\\"header\\\":\\\"Data Model\\\"}]\"}"}}Notice Because most downstream SDKs and clients strictly validate the incoming JSON against the tool's schema (which expects an |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
🏷️ Discussion Type
Bug
💬 Feature/Topic Area
Copilot in GitHub
Body
Summary
When streaming a tool call from
claude-opus-4.8through Copilot's nativeAnthropic endpoint (
POST /v1/messages,Accept: text/event-stream), thereassembled
tool_use.inputintermittently omits a field that the tool'sinput_schemadeclares asrequired. Theinput_json_delta.partial_jsonfragments that Copilot streams concatenate into JSON that is syntactically
valid but schema-invalid — a required property is simply absent.
For a tool like Anthropic's
AskUserQuestion(eachquestions[]item requiresquestion,header,options,multiSelect), the streamed input comes backwith the
questionfield missing from every question object, so any strictschema validator on the client rejects the tool call ("Invalid tool
parameters") and the turn fails.
This is non-deterministic: the same request shape succeeds most of the time and
fails a minority of the time, which points at the model/gateway streaming path
rather than a client bug.
Affected surface
POST https://api.<enterprise|business|individual>.githubcopilot.com/v1/messagesAccept: text/event-stream(streaming); also reproduced via the standard VS Code editor headersclaude-opus-4.8(primary). The same family streams tool calls the same way, soclaude-sonnet-4.6is likely also affected.stream:false) responses, wheretool_use.inputarrives as a single complete object.What I expected
The concatenation of all
input_json_delta.partial_jsonfragments for atool_usecontent block should reproduce a JSON object that satisfies thetool's declared
input_schema, including everyrequiredproperty — exactly asthe first-party Anthropic API does.
What actually happens
The concatenated fragments are valid JSON but missing a required field.
Example (real capture, reassembled from the streamed
partial_jsonfragments;the tool was
AskUserQuestion):{"questions":[ {"header":"Database","multiSelect":false,"options":[ ... ]}, {"header":"Deploy target","multiSelect":false,"options":[ ... ]} ]}Each
questions[]item is missing itsquestionproperty (required by thetool's schema). The fragment boundaries show the gap directly — two consecutive
input_json_deltaevents were:i.e. the
"question":"…",key/value pair that should sit between[{and"header"is absent from the stream itself.Frequency (measured)
Across 6 consecutive
AskUserQuestiontool calls in one session:questionfieldSo roughly 1–2 in 6 calls were affected. A tighter, isolated reproduction (below)
came back clean for 8/8 on one batch — consistent with a low-frequency,
non-deterministic omission rather than a deterministic failure.
Reproduction
Force a tool call with
tool_choiceso the model must emitAskUserQuestion,stream the response, and concatenate the
partial_jsonfragments. Repeat ~10–20times; a fraction will be missing the
questionfield.Then, for each response, concatenate every
data:event whosedelta.type == "input_json_delta"by theirpartial_json,JSON.parsethe result, and check that eachquestions[]item contains aquestionkey. A subset of runs will be missing it.Why this is server-side, not a client bug
I isolated the bridge/client out of the loop two ways:
Round-trip parser test. Feeding well-formed Anthropic tool-call SSE
(including fragment boundaries that split mid-key right before
question,CRLF line endings, and an empty first fragment) through a standard SSE parse +
re-serialize preserves every field byte-for-byte. The client never drops it
for well-formed input.
Raw byte read. Reading Copilot's response with a raw stream reader
(no SSE event framing / no reassembly logic at all) and concatenating the
partial_jsonfragments straight off the wire still shows the field missingon the affected runs. The omission is present in the bytes Copilot emits,
before any client-side parsing.
Impact
Any client that validates
tool_use.inputagainst the tool's declaredinput_schema(the Anthropic SDKs and Claude Code do) will reject the entiretool call when a required field is missing, failing the turn. Because it is
intermittent, it manifests as flaky "Invalid tool parameters" / "tool input did
not match schema" errors that are hard to attribute.
Environment
/v1/messagesendpointclaude-opus-4.8, streaming,tool_choiceforcing a specific toolSuggested fix
Ensure the streaming tool-call generation path emits the complete tool input —
specifically that every property the model produces (and at minimum every
requiredproperty per the tool'sinput_schema) is present in theconcatenated
input_json_deltafragments, matching first-party Anthropic APIbehavior. If the model occasionally produces incomplete tool JSON, consider
validating/repairing against the declared
input_schemabefore the stream isfinalized, or surfacing a clear
stop_reasonrather than emitting a silentlyincomplete object.
Beta Was this translation helpful? Give feedback.
All reactions