BerriAI/litellm · error · OCIError
Tool call `function.name` must be a string
Error message
Tool call `function.name` must be a string
What it means
The nested function object of a tool call must have a string 'name'. A missing, None, or non-string name raises OCIError(400) "Tool call `function.name` must be a string" before the request leaves the client. The name is required because OCI's OCIToolCall maps it to the FUNCTION tool invocation name.
Source
Thrown at litellm/llms/oci/chat/generic.py:133
"""Convert an assistant tool-call message to OCI format."""
tool_calls_formatted: Final = []
for tool_call in tool_calls:
if not isinstance(tool_call, dict):
raise OCIError(status_code=400, message="Each tool call must be a dictionary")
if tool_call.get("type") != "function":
raise OCIError(status_code=400, message="OCI only supports function tool calls")
tool_call_id = tool_call.get("id")
if not isinstance(tool_call_id, str):
raise OCIError(status_code=400, message="Tool call `id` must be a string")
tool_function = tool_call.get("function")
if not isinstance(tool_function, dict):
raise OCIError(status_code=400, message="Tool call `function` must be a dictionary")
function_name = tool_function.get("name")
if not isinstance(function_name, str):
raise OCIError(status_code=400, message="Tool call `function.name` must be a string")
arguments = tool_call["function"].get("arguments", "{}")
if not isinstance(arguments, str):
raise OCIError(
status_code=400,
message="Tool call `function.arguments` must be a JSON string",
)
tool_calls_formatted.append(
OCIToolCall(
id=tool_call_id,
type="FUNCTION",
name=function_name,
arguments=arguments,
)
)
return OCIMessage(View on GitHub (pinned to 6c2dcb801b)
Solutions
- Always set function.name to the exact tool name string that was declared in the tools parameter.
- Render-check templates so name is never empty.
- Pre-flight assert isinstance(tc['function'].get('name'), str) and it's non-empty.
Example fix
# before
{'id':'c1','type':'function','function':{'arguments':'{"city":"SF"}'}}
# after
{'id':'c1','type':'function','function':{'name':'get_weather','arguments':'{"city":"SF"}'}} Defensive patterns
Strategy: type-guard
Validate before calling
for tc in msg.get('tool_calls') or []:
fn = tc.get('function') or {}
assert isinstance(fn.get('name'), str) and fn['name'], f'tool call function.name missing: {tc!r}' Type guard
def tool_call_has_string_name(tc: object) -> bool:
return (
isinstance(tc, dict)
and isinstance(tc.get('function'), dict)
and isinstance(tc['function'].get('name'), str)
and bool(tc['function']['name'])
) Prevention
- Match function.name exactly to a name declared in the tools parameter of the same conversation.
- Template-render history with strict placeholders that fail loudly when a name is missing.
When it happens
Trigger: Sending {'id':'c1','type':'function','function':{'arguments':'{}'}} (name omitted) or with name set to None/numeric in assistant history to an oci/ GENERIC model.
Common situations: Synthetic few-shot tool turns built without names; templated history where the name placeholder failed to render; data pipelines that rename/drop the name key.
Related errors
- Tool call `id` must be a string
- Tool result message must have a string `tool_call_id`
- Each tool call must be a dictionary
- OCI only supports function tool calls
- Tool call `function` must be a dictionary
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/bf40b55828135b51.
Report an issue: GitHub.