BerriAI/litellm · error · Exception
Unable to convert openai tool calls={tool_calls} to bedrock
Error message
Unable to convert openai tool calls={tool_calls} to bedrock tool calls. Received error={e} What it means
A blanket except in _convert_to_bedrock_tool_call_invoke: any exception raised while mapping OpenAI assistant tool_calls to Bedrock Converse 'toolUse' blocks is re-raised with this message. Root causes are usually malformed tool_call dicts (missing 'id' or 'function', non-string arguments) or invalid JSON in arguments.
Source
Thrown at litellm/litellm_core_utils/prompt_templates/factory.py:3715
# Fallback: no objects extracted — use empty dict.
arguments_dict = {}
bedrock_tool = BedrockToolUseBlock(input=arguments_dict, name=name, toolUseId=tool_id)
bedrock_content_block = BedrockContentBlock(toolUse=bedrock_tool)
_parts_list.append(bedrock_content_block)
# Check for cache_control and add a separate cachePoint block
if tool.get("cache_control", None) is not None:
cache_point_block = litellm.AmazonConverseConfig().get_cache_point_block(
{"cache_control": tool["cache_control"]},
block_type="content_block",
model=model,
)
if cache_point_block is not None:
_parts_list.append(cache_point_block)
return _parts_list
except Exception as e:
raise Exception(f"Unable to convert openai tool calls={tool_calls} to bedrock tool calls. Received error={e}")
def _append_bedrock_tool_result_media_block(
tool_result_content_blocks: list[BedrockToolResultContentBlock],
processed_block: BedrockContentBlock,
content: dict,
content_type: str,
) -> None:
if "image" in processed_block:
tool_result_content_blocks.append(BedrockToolResultContentBlock(image=processed_block["image"]))
elif "document" in processed_block:
tool_result_content_blocks.append(BedrockToolResultContentBlock(document=processed_block["document"]))
else:
verbose_logger.warning(
"Bedrock Converse: unrecognized BedrockContentBlock keys %s for %s tool-result block %s; dropping.",
list(processed_block.keys()),
content_type,
content,View on GitHub (pinned to 6c2dcb801b)
Solutions
- Inspect the full exception text after 'Received error=' — it contains the underlying cause.
- Ensure each tool_call has string 'id', and 'function' with 'name' and JSON-string 'arguments'.
- Normalize provider-specific tool call objects to the OpenAI shape before sending history to Bedrock.
- If arguments is already a dict, json.dumps it first.
Example fix
# before
{"role": "assistant", "tool_calls": [{"function": {"name": "get_weather", "arguments": {"city": "SF"}}}]}
# after
import json
{"role": "assistant", "tool_calls": [{"id": "call_1", "type": "function", "function": {"name": "get_weather", "arguments": json.dumps({"city": "SF"})}}]} Defensive patterns
Strategy: validation
Validate before calling
def valid_openai_tool_call(tc: dict) -> bool:
return (
isinstance(tc.get("id"), str)
and isinstance(tc.get("function"), dict)
and isinstance(tc["function"].get("name"), str)
and isinstance(tc["function"].get("arguments"), str)
and _is_json(tc["function"]["arguments"])
)
def _is_json(s):
try:
json.loads(s); return True
except Exception:
return False Type guard
def is_openai_tool_call(x) -> bool:
return (
isinstance(x, dict)
and set(x) >= {"id", "type", "function"}
and x["type"] == "function"
and isinstance(x["function"], dict)
and {"name", "arguments"} <= set(x["function"])
) Try / catch
try:
resp = litellm.completion(model="bedrock/...", messages=history)
except Exception as e:
if "Unable to convert openai tool calls" in str(e):
history = [normalize_tool_calls(m) for m in history]
resp = litellm.completion(model="bedrock/...", messages=history) Prevention
- Always store assistant tool_calls verbatim from the model response and replay them unchanged.
- json.dumps arguments when building tool calls by hand.
- Validate history shape before replaying long conversations to Bedrock.
When it happens
Trigger: Calling a Bedrock Converse model with an assistant message whose tool_calls entries lack 'id', have 'function' missing 'name'/'arguments', or whose arguments are a dict-with-unserializable-values or a non-JSON string. Also triggered if a tool entry itself has an unexpected shape.
Common situations: Replaying stored/LLM-generated assistant messages into conversation history; hand-built tool_call dicts; tool call objects from another provider's schema (missing id); arguments already parsed as dict with weird types.
Related errors
- BedrockException - {error_str} . Enable 'litellm.modify_para
- Unsupported content type: {type(content_block)}
- tool call not supported: {tool_call}
- Chat provider: Invalid function argument delta {parsed_chunk
- Invalid completion response: no message found in choice
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/80af02434fffaf86.
Report an issue: GitHub.