{"record":{"id":"063630e483e3a01c","repo":"sgl-project/sglang","slug":"assistant-tool-call-function-arguments-must-be-a-j-063630","errorCode":null,"errorMessage":"Assistant tool call function.arguments must be a JSON object.","messagePattern":"Assistant tool call function\\.arguments must be a JSON object\\.","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"python/sglang/srt/entrypoints/openai/serving_chat.py","lineNumber":137,"sourceCode":"        for p in parts\n    )\n    if is_openai_text_parts:\n        text_parts = [p.get(\"text\", \"\") if isinstance(p, dict) else p for p in parts]\n        return \" \".join(text_parts)\n    return content\n\n\ndef parse_tool_call_arguments(arguments: str) -> Dict[str, Any]:\n    \"\"\"Parse OpenAI tool call arguments for chat templates.\"\"\"\n    try:\n        parsed_arguments = orjson.loads(arguments)\n    except orjson.JSONDecodeError as exc:\n        raise ValueError(\n            \"Assistant tool call function.arguments must be valid JSON.\"\n        ) from exc\n\n    if not isinstance(parsed_arguments, dict):\n        raise ValueError(\n            \"Assistant tool call function.arguments must be a JSON object.\"\n        )\n\n    return parsed_arguments\n\n\ndef normalize_assistant_tool_call_arguments(\n    message: Dict[str, Any], *, strict: bool = True\n) -> None:\n    \"\"\"Normalize assistant history tool call arguments in-place.\"\"\"\n    if message.get(\"role\") != \"assistant\" or not isinstance(\n        message.get(\"tool_calls\"), list\n    ):\n        return\n\n    for item in message[\"tool_calls\"]:\n        function = item.get(\"function\") if isinstance(item, dict) else None\n        if not isinstance(function, dict):","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/entrypoints/openai/serving_chat.py#L119-L155","documentation":"parse_tool_call_arguments requires the parsed arguments to be a JSON object (dict), not an array, string, or number. Tool arguments map parameter names to values, so scalars/lists are rejected after successful JSON parsing.","triggerScenarios":"Assistant tool_calls with arguments \"[1,2]\" or \"\\\"text\\\"\" — valid JSON but not an object.","commonSituations":"Wrapping arguments in an array because a model emitted them that way; sending a bare string for zero-arg functions instead of \"{}\".","solutions":["Use an object: '{\"query\": \"...\"}'","For no-argument tools send '{}' (empty object)"],"exampleFix":"// before\n\"arguments\": \"[\\\"SF\\\"]\"\n// after\n\"arguments\": \"{\\\"city\\\": \\\"SF\\\"}\"","handlingStrategy":"type-guard","validationCode":"parsed = json.loads(args)\nassert isinstance(parsed, dict), 'tool arguments must be a JSON object'","typeGuard":"def args_is_object(s):\n    try: return isinstance(json.loads(s), dict)\n    except Exception: return False","tryCatchPattern":"except ValueError as e: if 'JSON object' in str(e): wrap args as {\"value\": parsed} if appropriate","preventionTips":["Always serialize a dict, use '{}' for no-arg tools"],"tags":["tool-calling","json","validation","openai-api","sglang"],"backgroundTag":"invalid-json-in-request","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}