sgl-project/sglang · error · ValueError
Assistant tool call function.arguments must be valid JSON.
Error message
Assistant tool call function.arguments must be valid JSON.
What it means
parse_tool_call_arguments fails when an assistant message's tool_call function.arguments string is not valid JSON. Prior assistant turns are re-rendered through chat templates, so their arguments must parse as JSON (SGLang uses orjson).
Source
Thrown at python/sglang/srt/entrypoints/openai/serving_chat.py:132
if role != "tool" or not isinstance(content, list):
return content
parts = content
is_openai_text_parts = all(
(isinstance(p, dict) and p.get("type") == "text") or isinstance(p, str)
for p in parts
)
if is_openai_text_parts:
text_parts = [p.get("text", "") if isinstance(p, dict) else p for p in parts]
return " ".join(text_parts)
return content
def parse_tool_call_arguments(arguments: str) -> Dict[str, Any]:
"""Parse OpenAI tool call arguments for chat templates."""
try:
parsed_arguments = orjson.loads(arguments)
except orjson.JSONDecodeError as exc:
raise ValueError(
"Assistant tool call function.arguments must be valid JSON."
) from exc
if not isinstance(parsed_arguments, dict):
raise ValueError(
"Assistant tool call function.arguments must be a JSON object."
)
return parsed_arguments
def normalize_assistant_tool_call_arguments(
message: Dict[str, Any], *, strict: bool = True
) -> None:
"""Normalize assistant history tool call arguments in-place."""
if message.get("role") != "assistant" or not isinstance(
message.get("tool_calls"), list
):View on GitHub (pinned to 0132848349)
Solutions
- Ensure arguments is a serialized JSON object string, e.g. '{"city": "SF"}'
- If replaying streamed tool calls, accumulate argument fragments until finish_reason before sending back
- Repair malformed history with orjson.loads + json.dumps round-trip
Example fix
// before
{"role":"assistant","tool_calls":[{"id":"1","type":"function","function":{"name":"f","arguments":"{city: SF}"}}]}
// after
{"role":"assistant","tool_calls":[{"id":"1","type":"function","function":{"name":"f","arguments":"{\"city\": \"SF\"}"}}]} Defensive patterns
Strategy: validation
Validate before calling
import json
for tc in assistant_msg.get("tool_calls", []):
json.loads(tc["function"]["arguments"]) # must not raise Type guard
def valid_tool_call_args(s):
try:
return isinstance(json.loads(s), dict)
except (json.JSONDecodeError, TypeError):
return False Try / catch
except ValueError as e: if 'valid JSON' in str(e): repair args via json.dumps(parsed_obj) and resend
Prevention
- Accumulate streamed argument fragments until finish_reason before echoing back
- Round-trip histories through json.loads/dumps before resending
When it happens
Trigger: POST /v1/chat/completions with messages containing {"role":"assistant","tool_calls":[{"function":{"arguments":"not json"}}]}.
Common situations: Feeding back partial/streamed tool-call deltas whose arguments were concatenated incorrectly; models producing malformed arguments that are echoed back; hand-crafted conversation histories with placeholder arguments like '{...}'.
Related errors
- Assistant tool call function.arguments must be a JSON object
- tool_choice 'required' or a named tool cannot be combined wi
- --default-chat-template-kwargs must decode to a JSON object
- invalid reasoning effort: {effort!r}
- Value error, parameter top_n should be larger than 0.
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/f80fe575facd6fac.
Report an issue: GitHub.