BerriAI/litellm · error · OCIError
Tool call `function` must be a dictionary
Error message
Tool call `function` must be a dictionary
What it means
Inside each function tool call, the `function` field must be a dict containing name and arguments. If it is missing, None, a string (double-encoded JSON), or any non-dict, OCI translation aborts with OCIError 400. Mirrors the OpenAI tool-call structure that OCI GENERIC maps onto OCIToolCall.
Solutions
- Keep `function` a dict: {"name": ..., "arguments": "<json str>"}
- Repair double-encoded history at load: json.loads(tc["function"]) when it is a str
- Echo the structure exactly as returned by prior completion responses
- Validate history shape (see type guard) before the first OCI call
Example fix
# before
{"id":"1","type":"function","function":"{\"name\":\"get_weather\",\"arguments\":\"{}\"}"}
# after
{"id":"1","type":"function","function":{"name":"get_weather","arguments":"{}"}} Defensive patterns
Strategy: validation
Validate before calling
import json
def normalize_tool_call_function(tool_calls: list) -> list:
out = []
for tc in tool_calls:
fn = tc.get("function")
if isinstance(fn, str):
tc = {**tc, "function": json.loads(fn)}
out.append(tc)
return out Type guard
def tool_call_function_is_dict(tc) -> bool:
return isinstance(tc.get("function"), dict) Prevention
- Round-trip test your history store: save then load and assert the shape is unchanged
- Validate history at load time, not just at send time
When it happens
Trigger: Assistant history with tool_calls=[{"id":"1","type":"function","function":"{\"name\":\"f\"}"}] (function JSON-stringified) or with the function key omitted, sent to an oci/generic.* model.
Common situations: json.dumps applied one level too deep when persisting history; hand-crafted tool_calls from an LLM's raw text output parsed shallowly; frameworks storing function as a flat string for compactness; partial dict after aggressive key filtering.
Related errors
- Each tool call must be a dictionary
- Message `tool_calls` must be a list
- OCI only supports function tool calls
- Tool call `function.arguments` must be a JSON string
- Tool call `function.name` must be a string
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/34bbc070b088fe9c.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/llms/oci/chat/generic.py:129
)
def adapt_messages_to_generic_oci_standard_tool_call(role: str, tool_calls: list) -> OCIMessage:
"""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,View on GitHub (pinned to 77b7c6c40c)