{"record":{"id":"6d8fa767161a210b","repo":"BerriAI/litellm","slug":"function-call-missing-received-tool-call-with-ty-6d8fa7","errorCode":null,"errorMessage":"function_call missing. Received tool call with 'type': 'function'. No function call in argument - {message}","messagePattern":"function_call missing\\. Received tool call with 'type': 'function'\\. No function call in argument - (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/litellm_core_utils/prompt_templates/factory.py","lineNumber":1355,"sourceCode":"\n                # Extract thought signature from function_call's provider_specific_fields\n                thought_signature = None\n                provider_fields: Final = (\n                    function_call.get(\"provider_specific_fields\") if isinstance(function_call, dict) else {}\n                )\n                if isinstance(provider_fields, dict):\n                    thought_signature = provider_fields.get(\"thought_signature\")\n\n                # If no signature found and model is gemini-3, use dummy signature\n                if not thought_signature and model and VertexGeminiConfig._is_gemini_3_or_newer(model):\n                    thought_signature = _get_dummy_thought_signature()\n\n                if thought_signature:\n                    part_dict_function[\"thoughtSignature\"] = thought_signature\n\n                _parts_list.append(part_dict_function)\n            else:  # don't silently drop params. Make it clear to user what's happening.\n                raise Exception(\n                    f\"function_call missing. Received tool call with 'type': 'function'. No function call in argument - {message}\"\n                )\n        return _parts_list\n    except Exception as e:\n        raise Exception(f\"Unable to convert openai tool calls={message} to gemini tool calls. Received error={e}\")\n\n\ndef convert_to_gemini_tool_call_result(\n    message: ChatCompletionToolMessage | ChatCompletionFunctionMessage,\n    last_message_with_tool_calls: dict | None,\n    forward_function_call_id: bool = False,\n) -> VertexPartType | list[VertexPartType]:\n    \"\"\"\n    OpenAI message with a tool result looks like:\n    {\n        \"tool_call_id\": \"tool_1\",\n        \"role\": \"tool\",\n        \"content\": \"function result goes here\",","sourceCodeStart":1337,"sourceCodeEnd":1373,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/litellm_core_utils/prompt_templates/factory.py#L1337-L1373","documentation":"Same converter, different branch: here the assistant message used the legacy top-level `function_call` field (not tool_calls), and that function_call payload had no usable name/arguments, so the helper returned None and LiteLLM raises rather than dropping it. The full message is embedded in the error for diagnosis.","triggerScenarios":"messages=[{\"role\":\"assistant\", \"function_call\": {}}] or function_call with a falsy name sent to a Gemini/Vertex model; migrating legacy OpenAI function-calling histories where the function_call object lost its 'name'.","commonSituations":"Old logs in the pre-tool_calls 'function_call' format; merging histories from systems that stored None names; continuing conversations captured from very old OpenAI SDK versions.","solutions":["Fix the function_call payload to {\"name\": <str>, \"arguments\": <json str>}","Prefer the modern tool_calls format and migrate legacy histories once at load time","Validate/sanitize persisted histories before replaying them against Gemini"],"exampleFix":"# before\nhistory.append({\"role\": \"assistant\", \"function_call\": {\"arguments\": \"{\\\"x\\\": 1}\"}})\n\n# after\nhistory.append({\"role\": \"assistant\", \"function_call\": {\"name\": \"get_weather\", \"arguments\": \"{\\\"x\\\": 1}\"}})","handlingStrategy":"validation","validationCode":"def function_call_is_well_formed(fc) -> bool:\n    return isinstance(fc, dict) and bool(fc.get(\"name\")) and isinstance(fc.get(\"arguments\"), str)\n\nfor m in messages:\n    fc = m.get(\"function_call\")\n    if fc is not None and not function_call_is_well_formed(fc):\n        raise ValueError(f\"malformed function_call in message: {m}\")","typeGuard":"from typing import Any\n\ndef is_valid_function_call(fc: Any) -> bool:\n    return isinstance(fc, dict) and bool(fc.get(\"name\"))","tryCatchPattern":null,"preventionTips":["Migrate legacy function_call histories to tool_calls once at load","Reject stored function_call objects without a name","Run a schema check on imported conversations"],"tags":["gemini","vertex","function-call","legacy"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}