FlowiseAI/Flowise · error · Error

Google requires a tool name for each tool call response…

Error message

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.

What it means

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.

Solutions

  1. Set an explicit name on the ToolMessage matching the tool that was called.
  2. Preserve the originating AIMessage (with its tool_calls) earlier in the message array so inference can match tool_call_id.
  3. Ensure tool_call_id on the ToolMessage exactly equals the id of the corresponding tool_call in the preceding AIMessage.

Example fix

// before (throws): new ToolMessage({ content: '42', tool_call_id: 'call_1' })  // no name, no prior AI msg
// after:           new ToolMessage({ content: '42', tool_call_id: 'call_1', name: 'calculator' })
Defensive patterns

Strategy: validation

Validate before calling

import { AIMessage, ToolMessage, BaseMessage } from '@langchain/core/messages'

function toolMessagesNeedName(messages: BaseMessage[]): ToolMessage[] {
  const toolCallsById = new Map<string, string>() // id -> name
  for (const m of messages) {
    if (AIMessage.isInstance(m)) for (const tc of m.tool_calls ?? []) toolCallsById.set(tc.id, tc.name)
  }
  return messages.filter((m): m is ToolMessage =>
    ToolMessage.isInstance(m) && !m.name && !toolCallsById.has(m.tool_call_id)
}
// before invoke:
for (const tm of toolMessagesNeedName(messages)) {
  throw new Error(`ToolMessage ${tm.id} needs a name; set it or restore the prior AIMessage`)
}

Type guard

function isNamedToolMessage(m: unknown): boolean {
  return ToolMessage.isInstance(m) && typeof (m as ToolMessage).name === 'string' && (m as ToolMessage).name !== ''
}

Try / catch

try {
  return convertMessageContentToParts(message, isMultimodal, previousMessages)
} catch (e) {
  if (e instanceof Error && /Google requires a tool name/.test(e.message)) {
    // set message.name explicitly and retry, or restore the originating AIMessage
  }
  throw e
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12). Data as JSON: /api/errors/50692c4cd743efd0. Report an issue: GitHub.

Appendix: source

Thrown at packages/components/nodes/chatmodels/ChatGoogleGenerativeAI/FlowiseChatGoogleGenerativeAI.ts:323

    } else {
        if ('type' in content) {
            throw new Error(`Unknown content type ${content.type}`)
        } else {
            throw new Error(`Unknown content ${JSON.stringify(content)}`)
        }
    }
}

export function convertMessageContentToParts(
    message: BaseMessage,
    isMultimodalModel: boolean,
    previousMessages: BaseMessage[],
    model?: string
): Part[] {
    if (ToolMessage.isInstance(message)) {
        const messageName = message.name ?? inferToolNameFromPreviousMessages(message, previousMessages)
        if (messageName === undefined) {
            throw new Error(
                `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.`
            )
        }

        const result = Array.isArray(message.content)
            ? (message.content
                  .map((c) => _convertLangChainContentToPart(c as MessageContentComplex, isMultimodalModel))
                  .filter((p) => p !== undefined) as Part[])
            : message.content

        if (message.status === 'error') {
            return [
                {
                    functionResponse: {
                        name: messageName,
                        response: { error: { details: result } }
                    }
                }

View on GitHub (pinned to abe4a8601a)