{"record":{"id":"8554522c47658361","repo":"BerriAI/litellm","slug":"tool-call-function-arguments-must-be-a-json-stri","errorCode":null,"errorMessage":"Tool call `function.arguments` must be a JSON string","messagePattern":"Tool call `function\\.arguments` must be a JSON string","errorType":"validation","errorClass":"OCIError","httpStatus":400,"severity":"error","filePath":"litellm/llms/oci/chat/generic.py","lineNumber":137,"sourceCode":"            raise OCIError(status_code=400, message=\"Each tool call must be a dictionary\")\n        if tool_call.get(\"type\") != \"function\":\n            raise OCIError(status_code=400, message=\"OCI only supports function tool calls\")\n\n        tool_call_id = tool_call.get(\"id\")\n        if not isinstance(tool_call_id, str):\n            raise OCIError(status_code=400, message=\"Tool call `id` must be a string\")\n\n        tool_function = tool_call.get(\"function\")\n        if not isinstance(tool_function, dict):\n            raise OCIError(status_code=400, message=\"Tool call `function` must be a dictionary\")\n\n        function_name = tool_function.get(\"name\")\n        if not isinstance(function_name, str):\n            raise OCIError(status_code=400, message=\"Tool call `function.name` must be a string\")\n\n        arguments = tool_call[\"function\"].get(\"arguments\", \"{}\")\n        if not isinstance(arguments, str):\n            raise OCIError(\n                status_code=400,\n                message=\"Tool call `function.arguments` must be a JSON string\",\n            )\n\n        tool_calls_formatted.append(\n            OCIToolCall(\n                id=tool_call_id,\n                type=\"FUNCTION\",\n                name=function_name,\n                arguments=arguments,\n            )\n        )\n\n    return OCIMessage(\n        role=open_ai_to_generic_oci_role_map[role],\n        content=None,\n        toolCalls=tool_calls_formatted,\n        toolCallId=None,","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/oci/chat/generic.py#L119-L155","documentation":"Tool call arguments must be a JSON-encoded string (defaulting to '{}' when absent), matching the OpenAI wire format. Passing arguments as a dict/object instead of a serialized string raises OCIError(400) \"Tool call `function.arguments` must be a JSON string\" in the OCI GENERIC adapter.","triggerScenarios":"Sending {'function': {'name':'f','arguments': {'city':'SF'}}} — a live dict — in assistant tool-call history to an oci/ GENERIC model. This is the classic mistake when hand-building history instead of echoing back what the model produced.","commonSituations":"Developers writing arguments as objects because it reads nicer; frameworks that auto-serialize dicts and stop doing so after an upgrade; mixing conventions between request 'tools' (where parameters is a dict) and history 'tool_calls' (where arguments is a string).","solutions":["Serialize: arguments=json.dumps({...}).","Echo tool calls back verbatim from the model's own response instead of reconstructing them by hand.","Pre-flight: coerce with json.dumps if not isinstance(arguments, str)."],"exampleFix":"# before\n{'id':'c1','type':'function','function':{'name':'get_weather','arguments':{'city':'SF'}}}\n\n# after\nimport json\n{'id':'c1','type':'function','function':{'name':'get_weather','arguments':json.dumps({'city':'SF'})}}","handlingStrategy":"validation","validationCode":"import json\n\nfor tc in msg.get('tool_calls') or []:\n    args = tc.get('function', {}).get('arguments', '{}')\n    if not isinstance(args, str):\n        tc['function']['arguments'] = json.dumps(args)","typeGuard":"def tool_call_args_are_json_string(tc: object) -> bool:\n    args = tc.get('function', {}).get('arguments', '{}') if isinstance(tc, dict) else None\n    if not isinstance(args, str):\n        return False\n    try:\n        json.loads(args)\n        return True\n    except (TypeError, ValueError):\n        return False","tryCatchPattern":null,"preventionTips":["Remember the asymmetry: tools.parameters is a dict, tool_calls.function.arguments is a JSON string.","json.dumps at the boundary where tool results/history is built, never rely on the provider to coerce."],"tags":["oci","tool-calls","input-validation","json-serialization"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}