fix: sanitize malformed tool call arguments to prevent vLLM 400 errors - #13092
fix: sanitize malformed tool call arguments to prevent vLLM 400 errors#13092thanhnnict wants to merge 1 commit into
Conversation
When LLMs generate malformed JSON in tool_calls.function.arguments
(e.g., missing commas, truncated due to max_tokens), Continue stores
this in conversation history and sends it back to the server on
subsequent turns. vLLM validates JSON in tool_calls arguments during
request preprocessing and rejects malformed input with a 400 error.
Fix: validate JSON before sending tool_calls arguments back to server.
If invalid, wrap in a valid JSON envelope ({ _raw: original }) to
prevent server rejection while preserving the original content.
Root causes of malformed JSON:
1. max_tokens truncation cutting off mid-JSON
2. Reasoning token leak into arguments field
3. Model hallucination producing invalid syntax
4. Special characters not properly escaped
Related: vllm-project/vllm#43995
|
All contributors have signed the CLA ✍️ ✅ |
|
I have read the CLA Document and I hereby sign the CLA |
|
Hi @continuedev/maintainers, The failing checks ( The Could you confirm if these are pre-existing flaky tests or re-run the CI? Thanks! |
|
Hi @sestinj - Friendly ping on this PR. We have been hitting vLLM 400 errors in production when models produce truncated JSON in tool_calls arguments (especially under max_tokens pressure with Nemotron Ultra 253B). The sanitization is defensive - validates JSON before sending it back, zero impact on valid responses. Related upstream vLLM issue: vllm-project/vllm#43995 - Happy to add unit tests or adjust the wrapping strategy. Let me know if this aligns with the project direction. Thanks. |
Problem
When LLMs generate malformed JSON in
tool_calls.function.arguments(e.g., missing commas, truncated due tomax_tokens), Continue stores this in conversation history and sends it back to the server on subsequent turns. vLLM validates JSON in tool_calls arguments during request preprocessing and rejects malformed input with a 400 error, breaking the conversation.Solution
Validate JSON before sending tool_calls arguments back to server. If invalid, wrap in a valid JSON envelope (
{"_raw": original}) to prevent server rejection while preserving the original content.Behavior
{"path": "/tmp/x"}{"path": "/tmp/x" "content": "hi"}{"_raw": "..."}""(empty)"{}"(fallback)null/undefined"{}"(fallback)Root Causes of Malformed JSON
Trade-offs
JSON.parse()on every tool_call argument — negligible cost (microseconds){"_raw": "..."}may confuse model, but strictly better than 400 error_rawfieldRelated