{"record":{"id":"5c31dbd91445ba22","repo":"BerriAI/litellm","slug":"failed-to-parse-tool-call-arguments-error-origi","errorCode":null,"errorMessage":"Failed to parse tool call arguments. Error: {original_error}. Arguments: {arguments}","messagePattern":"Failed to parse tool call arguments\\. Error: (.+?)\\. Arguments: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/litellm_core_utils/prompt_templates/common_utils.py","lineNumber":1801,"sourceCode":"                \"Repaired truncated tool call arguments for tool '%s' (%s). Original (%d chars): %.200s%s\",\n                tool_name or \"<unknown>\",\n                context or \"unknown context\",\n                len(arguments),\n                arguments,\n                \"...\" if len(arguments) > 200 else \"\",\n            )\n            return repaired\n\n        error_parts: Final = [\"Failed to parse tool call arguments\"]\n\n        if tool_name:\n            error_parts.append(f\"for tool '{tool_name}'\")\n        if context:\n            error_parts.append(f\"({context})\")\n\n        error_message: Final = \" \".join(error_parts) + f\". Error: {original_error}. Arguments: {arguments}\"\n\n        raise ValueError(error_message) from original_error\n\n\ndef split_concatenated_json_objects(raw: str) -> list[dict[str, Any]]:\n    \"\"\"\n    Split a string that contains one or more concatenated JSON objects into\n    a list of parsed dicts.\n\n    LLM providers (notably Bedrock Claude Sonnet 4.5) sometimes return\n    multiple tool-call argument objects concatenated in a single\n    ``arguments`` string, e.g.::\n\n        '{\"command\":[\"curl\",...]}{\"command\":[\"curl\",...]}{\"command\":[\"curl\",...]}'\n\n    ``json.loads()`` fails on this with ``JSONDecodeError: Extra data``.\n    This helper uses ``json.JSONDecoder.raw_decode()`` to walk the string\n    and extract each JSON object individually.\n\n    Returns","sourceCodeStart":1783,"sourceCodeEnd":1819,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/litellm_core_utils/prompt_templates/common_utils.py#L1783-L1819","documentation":"LiteLLM raises this ValueError after it receives a model's tool call and tries to parse the `arguments` string as JSON; even its internal repair pass failed. The message includes the original JSON parse error, the offending tool name/context, and the raw arguments. It almost always means the LLM emitted malformed JSON (truncated, concatenated, or quote-mangled) rather than a problem with your request.","triggerScenarios":"Calling completion()/acompletion() with tools= against a model that returns a tool_call whose arguments are invalid JSON (e.g. single quotes, unescaped newlines, truncated output due to max_tokens, or multiple concatenated JSON objects that repair cannot split). Also triggered when a weaker model hallucinates non-JSON arguments.","commonSituations":"Small/open-source models (or high-temperature runs) producing unparseable tool arguments; max_tokens set so low the JSON is cut off; Bedrock Claude Sonnet 4.5 returning concatenated JSON objects in one arguments string; providers whose strict JSON mode is not enabled.","solutions":["Catch the ValueError and retry the request (optionally appending a corrective user message like 'Your tool arguments were invalid JSON, resend valid JSON')","Raise max_tokens so the tool call is not truncated mid-JSON","Switch to a model with reliable native function calling / strict tool-call JSON output","Pre-sanitize arguments yourself with a JSON repair pass (e.g. json_repair) before invoking the tool, if you are processing raw model output"],"exampleFix":"# before\nresp = litellm.completion(model=\"bedrock/anthropic.claude-3-5-sonnet\", messages=msgs, tools=tools)\nargs = json.loads(resp.choices[0].message.tool_calls[0].function.arguments)  # ValueError here\n\n# after\nimport json, litellm\n\nfor attempt in range(3):\n    try:\n        resp = litellm.completion(model=\"gpt-4o\", messages=msgs, tools=tools)\n        tc = resp.choices[0].message.tool_calls[0]\n        args = json.loads(tc.function.arguments)\n        break\n    except ValueError:\n        msgs.append({\"role\": \"assistant\", \"content\": resp.choices[0].message.content or \"\"})\n        msgs.append({\"role\": \"user\", \"content\": \"Your last tool arguments were invalid JSON. Resend the tool call with valid JSON.\"})","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    resp = litellm.completion(model=model, messages=messages, tools=tools)\n    args = json.loads(resp.choices[0].message.tool_calls[0].function.arguments)\nexcept ValueError as e:\n    if \"Failed to parse tool call arguments\" in str(e):\n        messages = messages + [\n            {\"role\": \"assistant\", \"content\": resp.choices[0].message.content or \"\"},\n            {\"role\": \"user\", \"content\": \"Your tool arguments were invalid JSON. Resend the tool call with valid JSON only.\"},\n        ]\n        resp = litellm.completion(model=model, messages=messages, tools=tools)\n    else:\n        raise","preventionTips":["Use models with native, reliable function calling","Set max_tokens high enough that tool-call JSON is never truncated","Keep temperature low when tool arguments are expected","Log raw tool_call arguments so malformed output is diagnosable"],"tags":["json","tool-calling","llm-response","parsing"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}