{"record":{"id":"50692c4cd743efd0","repo":"FlowiseAI/Flowise","slug":"google-requires-a-tool-name-for-each-tool-call-res","errorCode":null,"errorMessage":"Google requires a tool name for each tool call response, and we could not infer a called tool name for ToolMessage \"${message.id}\" from your passed messages. Please populate a \"name\" field on that ToolMessage explicitly.","messagePattern":"Google requires a tool name for each tool call response, and we could not infer a called tool name for ToolMessage \"(.+?)\" from your passed messages\\. Please populate a \"name\" field on that ToolMessage explicitly\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/components/nodes/chatmodels/ChatGoogleGenerativeAI/FlowiseChatGoogleGenerativeAI.ts","lineNumber":323,"sourceCode":"    } else {\n        if ('type' in content) {\n            throw new Error(`Unknown content type ${content.type}`)\n        } else {\n            throw new Error(`Unknown content ${JSON.stringify(content)}`)\n        }\n    }\n}\n\nexport function convertMessageContentToParts(\n    message: BaseMessage,\n    isMultimodalModel: boolean,\n    previousMessages: BaseMessage[],\n    model?: string\n): Part[] {\n    if (ToolMessage.isInstance(message)) {\n        const messageName = message.name ?? inferToolNameFromPreviousMessages(message, previousMessages)\n        if (messageName === undefined) {\n            throw new Error(\n                `Google requires a tool name for each tool call response, and we could not infer a called tool name for ToolMessage \"${message.id}\" from your passed messages. Please populate a \"name\" field on that ToolMessage explicitly.`\n            )\n        }\n\n        const result = Array.isArray(message.content)\n            ? (message.content\n                  .map((c) => _convertLangChainContentToPart(c as MessageContentComplex, isMultimodalModel))\n                  .filter((p) => p !== undefined) as Part[])\n            : message.content\n\n        if (message.status === 'error') {\n            return [\n                {\n                    functionResponse: {\n                        name: messageName,\n                        response: { error: { details: result } }\n                    }\n                }","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/FlowiseAI/Flowise/blob/abe4a8601a058047b350c260676826e21dd14101/packages/components/nodes/chatmodels/ChatGoogleGenerativeAI/FlowiseChatGoogleGenerativeAI.ts#L305-L341","documentation":"Thrown in convertMessageContentToParts (line 323) when a ToolMessage has no name and inferToolNameFromPreviousMessages() cannot match its tool_call_id to a prior AIMessage tool_call. Gemini's API requires each function/tool response to carry the called tool's name, so the converter refuses to emit an unnamed functionResponse.","triggerScenarios":"A ToolMessage with name===undefined is converted, and none of the preceding AIMessages contain a tool_call whose id equals the ToolMessage's tool_call_id.","commonSituations":"Message history was trimmed/summarized so the originating AIMessage with tool_calls is gone, tool_call_id/name is mismatched between the AI and Tool messages, or a manually constructed ToolMessage omits name.","solutions":["Set an explicit name on the ToolMessage matching the tool that was called.","Preserve the originating AIMessage (with its tool_calls) earlier in the message array so inference can match tool_call_id.","Ensure tool_call_id on the ToolMessage exactly equals the id of the corresponding tool_call in the preceding AIMessage."],"exampleFix":"// before (throws): new ToolMessage({ content: '42', tool_call_id: 'call_1' })  // no name, no prior AI msg\n// after:           new ToolMessage({ content: '42', tool_call_id: 'call_1', name: 'calculator' })","handlingStrategy":"validation","validationCode":"import { AIMessage, ToolMessage, BaseMessage } from '@langchain/core/messages'\n\nfunction toolMessagesNeedName(messages: BaseMessage[]): ToolMessage[] {\n  const toolCallsById = new Map<string, string>() // id -> name\n  for (const m of messages) {\n    if (AIMessage.isInstance(m)) for (const tc of m.tool_calls ?? []) toolCallsById.set(tc.id, tc.name)\n  }\n  return messages.filter((m): m is ToolMessage =>\n    ToolMessage.isInstance(m) && !m.name && !toolCallsById.has(m.tool_call_id)\n}\n// before invoke:\nfor (const tm of toolMessagesNeedName(messages)) {\n  throw new Error(`ToolMessage ${tm.id} needs a name; set it or restore the prior AIMessage`)\n}","typeGuard":"function isNamedToolMessage(m: unknown): boolean {\n  return ToolMessage.isInstance(m) && typeof (m as ToolMessage).name === 'string' && (m as ToolMessage).name !== ''\n}","tryCatchPattern":"try {\n  return convertMessageContentToParts(message, isMultimodal, previousMessages)\n} catch (e) {\n  if (e instanceof Error && /Google requires a tool name/.test(e.message)) {\n    // set message.name explicitly and retry, or restore the originating AIMessage\n  }\n  throw e\n}","preventionTips":["Always set name on ToolMessage at construction time.","Avoid trimming the originating AIMessage when summarizing history.","Keep tool_call_id consistent between AIMessage tool_calls and the ToolMessage response."],"tags":["gemini","tool-calling","messages","validation"],"backgroundTag":null,"analyzedSha":"abe4a8601a058047b350c260676826e21dd14101","analyzedAt":"2026-08-12T16:04:40.823Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}