fix(claude): collapse invalid tool_call Arguments to empty object (not just empty)#895
Open
gutopolewacz wants to merge 1 commit into
Open
Conversation
gutopolewacz
force-pushed
the
fix/claude-invalid-toolcall-args
branch
from
June 24, 2026 13:17
7f7d020 to
e7dbd25
Compare
convSchemaMessage only guarded Function.Arguments against the empty case before wrapping it in json.RawMessage. A streamed tool_use truncated mid-payload leaves Arguments as incomplete JSON; passing it raw to NewToolUseBlock makes ToolUseBlockParam.MarshalJSON fail with "unexpected end of JSON input" on request re-assembly, crashing the run. Generalize the guard to any non-valid-JSON Arguments (json.Valid), extending the empty-arg fix from cloudwego#462 to the invalid/truncated case. Valid JSON passes through unchanged. Fixes cloudwego#894
gutopolewacz
force-pushed
the
fix/claude-invalid-toolcall-args
branch
from
July 14, 2026 16:06
e7dbd25 to
34ee940
Compare
Author
|
Rebased onto latest main and resolved the conflict in |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
convSchemaMessage(components/model/claude/claude.go) only collapsed an empty tool-callArgumentsto"{}"before wrapping it injson.RawMessage. A non-empty but invalidArguments— typically a streamedtool_usetruncated mid-payload (theinput_json_deltachunks are cut before the JSON object closes) — was passed through raw, soToolUseBlockParam.MarshalJSONfailed on the next request re-assembly:This is the same crash as #462 (empty arg, already fixed by the
if args == ""guard) and the same family as #304 — but for the invalid/truncated sub-case, which the guard didn't cover. Closes #894.How
Generalize the existing guard to any non-valid-JSON
Argumentsviajson.Valid:Valid JSON passes through unchanged; empty/invalid both collapse to a valid empty object so marshaling succeeds and the run continues (the model gets a normal tool result and can retry) instead of crashing.
encoding/jsonis already imported.Tests
Added
Test_convSchemaMessage_ToolCallArgumentscovering: valid args pass through, empty →{}, truncated →{}, malformed →{}, and asserting the assembledMessageParammarshals without error.Note: I couldn't run the package test binary locally —
mockey v1.2.13fails to build on my toolchain (go1.26 / darwin-arm64:relocation target runtime.duffcopy not defined), which is unrelated to this change (it fails for any test in the package). The non-test package builds andgo vetis clean; CI should exercise the new test on a compatible toolchain. The new test does not use mockey.Why it helps others
We hit this in production in a Go agent harness on Eino's DeepAgent: an agent asked to write a large JSON file in one
write_filehad its tool_use stream truncate, crashing the whole turn. We worked around it downstream by wrapping the public model interface and sanitizingArgumentson the model boundary — but that's a per-consumer patch for what is a one-line generalization here. Fixing it upstream protects every Eino+Claude streaming user against the same crash, exactly as the empty-arg guard already does.