{"record":{"id":"80af02434fffaf86","repo":"BerriAI/litellm","slug":"unable-to-convert-openai-tool-calls-tool-calls-t","errorCode":null,"errorMessage":"Unable to convert openai tool calls={tool_calls} to bedrock tool calls. Received error={e}","messagePattern":"Unable to convert openai tool calls=(.+?) to bedrock tool calls\\. Received error=(.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/litellm_core_utils/prompt_templates/factory.py","lineNumber":3715,"sourceCode":"                        # Fallback: no objects extracted — use empty dict.\n                        arguments_dict = {}\n\n                bedrock_tool = BedrockToolUseBlock(input=arguments_dict, name=name, toolUseId=tool_id)\n                bedrock_content_block = BedrockContentBlock(toolUse=bedrock_tool)\n                _parts_list.append(bedrock_content_block)\n\n                # Check for cache_control and add a separate cachePoint block\n                if tool.get(\"cache_control\", None) is not None:\n                    cache_point_block = litellm.AmazonConverseConfig().get_cache_point_block(\n                        {\"cache_control\": tool[\"cache_control\"]},\n                        block_type=\"content_block\",\n                        model=model,\n                    )\n                    if cache_point_block is not None:\n                        _parts_list.append(cache_point_block)\n        return _parts_list\n    except Exception as e:\n        raise Exception(f\"Unable to convert openai tool calls={tool_calls} to bedrock tool calls. Received error={e}\")\n\n\ndef _append_bedrock_tool_result_media_block(\n    tool_result_content_blocks: list[BedrockToolResultContentBlock],\n    processed_block: BedrockContentBlock,\n    content: dict,\n    content_type: str,\n) -> None:\n    if \"image\" in processed_block:\n        tool_result_content_blocks.append(BedrockToolResultContentBlock(image=processed_block[\"image\"]))\n    elif \"document\" in processed_block:\n        tool_result_content_blocks.append(BedrockToolResultContentBlock(document=processed_block[\"document\"]))\n    else:\n        verbose_logger.warning(\n            \"Bedrock Converse: unrecognized BedrockContentBlock keys %s for %s tool-result block %s; dropping.\",\n            list(processed_block.keys()),\n            content_type,\n            content,","sourceCodeStart":3697,"sourceCodeEnd":3733,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/litellm_core_utils/prompt_templates/factory.py#L3697-L3733","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\n{\"role\": \"assistant\", \"tool_calls\": [{\"function\": {\"name\": \"get_weather\", \"arguments\": {\"city\": \"SF\"}}}]}\n# after\nimport json\n{\"role\": \"assistant\", \"tool_calls\": [{\"id\": \"call_1\", \"type\": \"function\", \"function\": {\"name\": \"get_weather\", \"arguments\": json.dumps({\"city\": \"SF\"})}}]}","handlingStrategy":"validation","validationCode":"def valid_openai_tool_call(tc: dict) -> bool:\n    return (\n        isinstance(tc.get(\"id\"), str)\n        and isinstance(tc.get(\"function\"), dict)\n        and isinstance(tc[\"function\"].get(\"name\"), str)\n        and isinstance(tc[\"function\"].get(\"arguments\"), str)\n        and _is_json(tc[\"function\"][\"arguments\"])\n    )\n\ndef _is_json(s):\n    try:\n        json.loads(s); return True\n    except Exception:\n        return False","typeGuard":"def is_openai_tool_call(x) -> bool:\n    return (\n        isinstance(x, dict)\n        and set(x) >= {\"id\", \"type\", \"function\"}\n        and x[\"type\"] == \"function\"\n        and isinstance(x[\"function\"], dict)\n        and {\"name\", \"arguments\"} <= set(x[\"function\"])\n    )","tryCatchPattern":"try:\n    resp = litellm.completion(model=\"bedrock/...\", messages=history)\nexcept Exception as e:\n    if \"Unable to convert openai tool calls\" in str(e):\n        history = [normalize_tool_calls(m) for m in history]\n        resp = litellm.completion(model=\"bedrock/...\", messages=history)","preventionTips":["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."],"tags":["bedrock","tool-calls","function-calling","message-format"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}