Gemini 3 + AI Agent + Postgres Chat Memory: parallel tool calls stored without thought_signature → 400 on next turn with the Vertex node (regression after 2.25.7)

Describe the problem/error/question

An AI Agent (@n8n/n8n-nodes-langchain.agent) using gemini-3-flash-preview with Postgres Chat Memory and tools fails on multi-turn conversations: the turn that makes parallel tool calls succeeds, but the next turn fails with a 400 from the model, before any tool runs.

Root cause: when Gemini 3 returns parallel function calls in one step, n8n persists AI messages to Postgres Chat Memory whose function calls are missing their thought_signature (the re-emitted single-call message is stored with additional_kwargs: {}). On the next turn this history is replayed, and the Google Vertex Chat Model node rejects it with a 400 (missing thought_signature).

This is endpoint-sensitive, and looks like a regression:

  • Google Vertex Chat Model → 400 on the turn after a parallel-call turn.
  • Google Gemini Chat Model (consumer API) → tolerates the same missing signatures (no error), so it masks the bug.
  • On an older n8n version the same workflow stored a single, signed tool-call message per turn and never failed; after upgrading to 2.25.7 it stores parallel calls without signatures and the next turn 400s on Vertex.

Steps to reproduce (deterministic, ~6 nodes)

  1. Chat Trigger → AI Agent + Google Vertex Chat Model (gemini-3-flash-preview) + Postgres Chat Memory + 2 trivial Code tools, with a system prompt that forces the model to call both tools in parallel every turn (workflow below).
  2. Turn 1 in a fresh chat (e.g. hi): agent calls both tools in parallel → succeeds.
  3. Turn 2 (same chat, even text-only): first LLM call → 400 before any tool runs.

Using the Google Gemini Chat Model (consumer) node instead, the exact same workflow runs fine for many turns — it tolerates the missing signatures. So the malformed history is produced regardless of endpoint; only Vertex enforces and rejects it.

My questions

  1. Is this a known regression in 2.25.7 in how the AI Agent serializes Gemini thought_signatures to chat memory for parallel tool calls (re-emitted call stored with additional_kwargs: {})?
  2. Which n8n version persists parallel-call signatures correctly, so I can pin to it?
  3. Any supported workaround besides downgrading, avoiding parallel tool calls, or stripping tool-call messages from memory between turns?

What is the error message (if any)?

n8n wrapper error on the Chat Model node:

Bad request - please check your parameters

Underlying Google API 400 by node:

  • Vertex node: function call is missing a thought_signature.
  • Gemini consumer node: tolerates missing signatures (no error). It only 400s with a corrupted thought_signature if a session mixes endpoints (Vertex-generated signature replayed through the consumer API).

Please share your workflow

Minimal reproduction (replace YOUR_GCP_PROJECT, add your Vertex credential on the model node and a Postgres credential on the memory node — no other data needed):

Share the output returned by the last node

The failing turn never reaches the last node — the Agent’s first LLM call 400s. The cause is visible in the n8n_chat_histories rows written by the previous turn (one parallel-call turn shown):

ai   | tool_calls: [tool_a, tool_b]   | additional_kwargs.__gemini_function_call_thought_signatures__: { tool_a_id: "<sig>" }   // only 1 sig for 2 calls
tool | tool_a result
ai   | tool_calls: [tool_b]           | additional_kwargs: {}    // <-- re-emitted call, NO thought_signature
tool | tool_b result
ai   | "done"

With the Vertex node, the next turn replaying this 400s. With the consumer Gemini node, the identical history is stored but the next turn succeeds (signatures are not enforced). On the older n8n version, the same turn instead stored a single consolidated tool-call message with its signature, and replays never failed.

Information on your n8n setup

n8n version: 2.25.7 (reproduces on n8n Cloud and self-hosted Docker 2.25.7 with the Vertex node; did not reproduce on an older self-hosted version)

Database (default: SQLite): PostgreSQL (Postgres Chat Memory)

n8n EXECUTIONS_PROCESS setting (default: own, main): default

Running n8n via (Docker, npm, n8n cloud, desktop app): n8n Cloud and self-hosted Docker

Operating system: Linux (Docker, VPS) / n8n Cloud

Hi @Ori_Yona

This sounds like a regression. You can add the following into the system prompt
"You MUST call only ONE tool per response. Never call multiple tools simultaneously. "

Let me know if it works.

Last choice would be to revert n8n to version before 2.25.7

Doesn’t seem to work persistenly, and i actually like that it sends paralllel tool calls, because in my actual workflow it’s an intermidate message to the user while searching the knowledge with sql tools, so it can get long, and + i believe its more token efficent.

Is there any way to downgrade a n8n cloud version?

Can you try the dropdown menu?

@Ori_Yona :white_check_mark: Managing complex AI agent memory and parallel tool-call signatures in n8n requires deep architectural knowledge, especially when debugging Vertex API regressions.

:white_check_mark: If you are looking to resolve these stability issues or need a senior-level automation expert to audit and optimize your production workflows, I invite you to explore my agency’s capabilities here: https://automaelite.com/.

:white_check_mark: I specialize in building, fixing, and scaling high-performance n8n, AI, Make.com, and GHL systems for serious agencies.

I can only choose between the latest stable or the beta.
The beta version doesn’t solve it as well.

@Ori_Yona

Since this is a Cloud-managed failure:

  1. Open a support ticket via the n8n Cloud dashboard.
  2. Indicate that version prior to 2.25.7 has no issue
  3. Mention that you have already tried switching between Stable and Beta and that the issue persists. This tells them it is a build-level dependency mismatch and not a user error, which usually escalates the ticket to the engineering team faster.

Ori, if Stable and Beta both fail, the downgrade path is probably the wrong lever now. The next thing worth proving is where the signature disappears: after the successful parallel-tool turn, grab the stored assistant message from Postgres Chat Memory and redact the content/tool args, leaving the keys around additional_kwargs / tool_calls visible.

If that stored row already has no thought_signature, the support ticket can be very narrow: Vertex rejects replayed memory after a parallel-tool turn because n8n stores the AI message without the signature. Can you post one redacted stored assistant-message row from immediately before the failing next turn?

This looks like a bug worth reporting directly at GitHub - n8n-io/n8n: Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations. · GitHub - the Postgres Chat Memory node should preserve thought_signature fields when storing parallel tool call results. As a workaround while waiting for a fix, you can try switching the memory node to “Window Buffer Memory” (in-memory) - it avoids the Postgres round-trip entirely and the Vertex node won’t hit the missing-signature issue since history stays in the same execution context. It’s not persistent across sessions but it works for multi-turn within a single session.

Here are the stored rows from Postgres immediately after the parallel tool call turn, confirming what’s in the DB before the failing next turn.

Row A (correct — one AI message with both parallel calls):

{
  "type": "ai",
  "content": "Calling tools: tool_a, tool_b",
  "tool_calls": [
    {"id": "ffcd9adc...", "name": "tool_a", "args": {"input": "test"}, "type": "tool_call"},
    {"id": "68f56e2d...", "name": "tool_b", "args": {"input": "test"}, "type": "tool_call"}
  ],
  "additional_kwargs": {
    "signatures": ["", "[REDACTED]", ""],
    "__gemini_function_call_thought_signatures__": {
      "ffcd9adc...": "[REDACTED]"
    }
  }
}

Row B (spurious — should NOT exist):

{
  "type": "ai",
  "content": "Calling tool_b with input: {\"input\":\"test\"}",
  "tool_calls": [
    {"id": "68f56e2d...", "name": "tool_b", "args": {"input": "test"}, "type": "tool_call"}
  ],
  "additional_kwargs": {}
}

Key findings:

  1. A second spurious AI message for tool_b alone is written to DB — it doesn’t exist in Gemini’s original response. It’s synthesized because tool_b’s intermediateStep.action.messageLog is empty in n8n’s executeBatch.ts.
  2. signatures has 3 entries for 2 tool calls — off-by-one bug.
  3. __gemini_function_call_thought_signatures__ only contains tool_a’s ID — tool_b missing entirely.
  4. Row B has additional_kwargs: {} — completely empty, no signature.

This confirms the issue is in n8n’s serialization layer, not in Gemini. Filed a GitHub issue here: [Bug] AI Agent V3 + Postgres Chat Memory: parallel tool calls write spurious second AI message to DB → malformed Gemini history → HTTP 400 on next turn (regression since 2.25.7) · Issue #32271 · n8n-io/n8n · GitHub

Ori, that row pair is the useful proof. Row B is the breakage shape: n8n is writing a second AI message that Gemini did not send, and that synthetic row has no signature metadata to replay.

That keeps the issue narrow: not prompt setup or Vertex config, but Agent V3/Postgres memory serialization around parallel tool calls. Since #32271 is already filed and marked in Linear, the only extra detail worth adding there is the exact n8n Cloud build/runtime if you have something more specific than 2.25.7.

@Ori_Yona i was in github deparment before this one is old error i remember it as handled both cases thought they fixed it tho was reported too hmi foward this to n8n team in discord