n8n sub-agents with no chat memory: pass the main agent's session ID down
A sub-workflow starts from its own trigger, so its memory node has no session. Send the session ID as a workflow input and key the sub-agent's memory on it.
Disclosure: I work on MemorySync (I'm Mohammed, the founder). I drafted this article with AI assistance and checked it against the n8n forum thread, the official n8n docs and the MemorySync docs listed under Sources on Oct 29, 2026. Code status: the node settings and expressions below are adapted from those docs and from the workflow shared in the thread, and were not run. I didn't run an n8n instance, a sub-workflow or a MemorySync request for this article.
In the n8n forum thread "My sub agents doesnt have chat memory" (May 6, 2025), a builder with specialised sub-agents and Postgres as memory wrote: "When i add postgres to my sub agents, the workflow doesnt start. If i dont use postgres on my sub agents, the agent can aswer the same message 10 times." The reply from another member was one line plus an example workflow: "You can pass the session id down to your sub agents so it remembers."
That is the whole fix, but it has a few moving parts: a sub-workflow input, a tool input, a memory Session Key, and a choice about whether the sub-agent should share the main conversation or keep its own. This page walks through each one. n8n behaviour comes from n8n's docs and the thread. If you want long-term facts about the person to reach every agent, the last part uses the MemorySync n8n guide as the example. Installing that node is covered in my earlier tutorial, Adding chat memory to an n8n agent with MemorySync, so it isn't repeated here.
Skip the memory plumbing around this setup. Once the steps below are in place, the MemorySync n8n guide shows how to add per-user memory with MemorySync. MemorySync doesn't replace the per-conversation session setup. When you're ready, see MemorySync. Founding offer: use code FOUNDING30 for 30% off Starter for your first 3 months (Settings → Billing).
Step 1: Know why the sub-agent has no session
A sub-workflow doesn't start from your Chat Trigger. Per the Execute Sub-workflow Trigger docs, it starts from the Execute Sub-workflow Trigger (also titled "When Executed by Another Workflow" when you search the trigger list), which runs when the Execute Sub-workflow or Call n8n Workflow Tool node calls it. It only receives the data the caller sends.
Memory nodes need a session key. Per the Simple Memory common issues page, "in most cases, the sessionId is automatically retrieved from the On Chat Message trigger", and if you're not using that trigger, "you'll need to manage sessions manually." Inside a sub-workflow there is no Chat Trigger, so a memory node left on its default has nothing to read.
The thread doesn't say why the workflow stopped starting. One documented cause worth checking: the same trigger page says that if there are errors in the sub-workflow, the parent workflow can't trigger it. A memory node with no usable session key is a likely candidate, but that's my guess, not something the thread confirms.
Step 2: Add a session input to the sub-workflow
Open the sub-workflow and set the Execute Sub-workflow Trigger's Input data mode. The thread's example uses Define using JSON example with two fields, a query and the main session:
{
"query": "query",
"sessionId": "sessionid"
}
(The thread names the second field mainsession; any name works as long as you use it consistently.) Define using fields below works too: add query and sessionId as strings. Per the docs, the calling node then pulls these fields in automatically.
If you plan to give the sub-agent long-term memory keyed by the person (Step 7), add a userId field now as well.
Step 3: Fill the session from the main workflow, not from the model
In the main workflow, the sub-agent is usually a Call n8n Workflow Tool on the main AI Agent's Tools. Per the Call n8n Workflow Tool docs, with Source: Database, once you pick the sub-workflow you can press Refresh to load its inputs and set each one with a fixed value, an expression on the current workflow's data, or a value the model fills in.
Use an expression for the session and let the model fill only the question:
sessionId: drag the Chat Trigger's
sessionIdfrom the input panel into the field (Expression mode), or reference the trigger node directly. With the default trigger name that is:{{ $('When chat message received').first().json.sessionId }}$("<node-name>").first()returns the first item that node output (n8n expression reference).query: let the model write it with
$fromAI()(docs):{{ $fromAI('query', 'The user question for this specialist', 'string') }}
Why not let the model pass the session ID? The thread's example does: the main agent's system message tells it to "pass the query and session id: {{ $json.sessionId }} to the "subagent" tool." It worked in the posted transcript, the sub-agent remembered "red", but one reply also read "It seems you mentioned a session ID again", so the ID leaked into the conversation. An expression keeps the key out of the model's hands: the value is the same on every call, and the model can't mistype it.
Give the tool a specific Description too. Per the docs, it tells the agent when to use the tool.
Step 4: Key the sub-agent's memory on that input
In the sub-workflow, attach a memory node to the sub-agent and set its session key yourself instead of taking it from a chat trigger. In the thread's example that's a Simple Memory node with a custom key:
Session Key: {{ $json.sessionId }}
Both Simple Memory and Postgres Chat Memory have a Session Key parameter. Per those pages, an expression in a sub-node always resolves to the first input item, which is fine here: the trigger passes one item with one session.
For a sub-agent in another workflow, I'd use a database-backed memory such as Postgres Chat Memory (what the thread's author already uses) rather than Simple Memory. Simple Memory's docs also say it doesn't work in an active production workflow in queue mode, because n8n can't make sure every call reaches the same worker.
Step 5: Decide: share the main conversation, or keep a sub-agent history
The Postgres Chat Memory page says that if you add more than one Postgres Chat Memory node, they all access the same memory instance by default, and that you set different session IDs to get separate memory instances. Simple Memory's common-issues page says the same. So the Session Key is your switch:
| Sub-agent Session Key | What the sub-agent sees (same credential and Table Name) |
|---|---|
{{ $json.sessionId }} (same as the main agent) |
The main conversation's history, and its own exchanges are added to it |
{{ $json.sessionId }}:colors (derived) |
Only its own earlier exchanges in this conversation, kept apart from the main history |
How I'd choose (my suggestion, not an n8n rule): share the key when the sub-agent needs to know what the person said earlier in the chat. Use a derived key when it only needs its own previous answers, so the main history doesn't fill up with delegated questions. Either way, the key changes when the conversation changes, so two people never share a sub-agent history.
Step 6: If you use the AI Agent Tool node instead
Per the AI Agent Tool docs, the AI Agent Tool node lets the main agent call other agents as tools inside one workflow, "without the complexity of managing context and variables that sub-workflows require." Its docs page lists Description, Prompt, System Message and batch options, and doesn't document a memory setting.
Because it lives in the same workflow as the Chat Trigger, there is no input to pass. If your n8n version shows a Memory connector on the node and you attach a memory node there, set its Session Key with the same trigger expression as Step 3 (or the derived form from Step 5). If not, put the context the specialist needs into its Prompt, for example with $fromAI().
Step 7: Share long-term facts across all agents (MemorySync example)
Steps 1 to 6 share chat history inside one conversation. They don't let a sub-agent know a person's preferences from last week's chat, because a new session starts empty. That needs memory keyed by the person, and it's where MemorySync (which I build) fits.
Per the MemorySync n8n guide:
- The MemorySync Chat Memory sub-node goes on an AI Agent's Memory port and takes a Session ID (your conversation key) and an End User ID (the person chatting, for example your app's internal user ID or an email address).
- Transcript turns are kept under an
n8n::<session>history scope: a separate transcript per session, with the same shared user memories as every other MemorySync surface. - MemorySync extracts durable facts from the user's turns only, and only those facts appear as memories.
- The MemorySync node's Search Memories operation is marked usable as a tool, so an agent can look up long-term facts on its own. Every operation is scoped by End User ID, and the guide says to use the same value everywhere or recall returns nothing.
A setup that follows from that:
- Main agent: MemorySync Chat Memory with Session ID
{{ $json.sessionId }}and End User ID from your own auth data. - Pass
userIdinto the sub-workflow next tosessionId(Step 2 and Step 3), again as an expression, not a model-filled value. - Sub-agents: attach a MemorySync node set to Search Memories as a tool, with End User ID
{{ $json.userId }}. They read the person's facts without writing to the transcript.
One thing to weigh before you also put Chat Memory on a sub-agent: there, the "user" message is whatever the main agent sent, and the guide says user turns are sent for fact extraction. If you'd rather only the person's own words feed long-term memory, keep Chat Memory on the main agent and give sub-agents the search tool.
Requirements per the guide: a self-managed n8n instance with community nodes (n8n Cloud verification is in progress), n8n 2.16.0 or later for the Chat Memory sub-node, and an API key with Write turned on under Permissions (new keys start read-only). The install and credential steps are in the earlier tutorial.
Skip the plumbing with MemorySync
Disclosure: I build MemorySync.
This doesn't change the fix above; it's the memory layer around it. The guide's MemorySync Chat Memory sub-node plugs into an AI Agent's Memory port and keeps that agent's conversation history in MemorySync, keyed by a Session ID plus an End User ID. For this page's problem, the wiring I'd use is Chat Memory on the parent only, and pass userId into the sub-agent workflow for a Search Memories tool:
AI Agent (parent) -> Memory: MemorySync Chat Memory
Session ID: {{ $json.sessionId }}
End User ID: {{ $json.userId }} # from your own auth data; the Chat Trigger doesn't send one by default
Context Window Length: 10
AI Agent (sub-agent workflow, receives sessionId + userId from the parent)
-> Tools: MemorySync (Search Memories)
End User ID: {{ $json.userId }}
Unverified (not run): the node settings come from the MemorySync n8n guide; passing userId to a sub-agent search tool is my wiring, not something the guide documents, and I haven't run it. The package installs from n8n's community-nodes panel on self-managed n8n (n8n-nodes-memorysync).
Try it: MemorySync is optional here: the steps above work without it. If you want the memory layer from the snippet, see MemorySync, create an API key in the dashboard and drop the snippet into your agent.
Troubleshooting
- The sub-agent's memory node reports "No sessionId". It's still looking for a chat trigger. Set its session key yourself to
{{ $json.sessionId }}(Step 4), and check the Execute Sub-workflow Trigger defines that input (Step 2). Per the common issues page, first check that your Chat Trigger's output includes asessionId. - Works in the editor, fails in production. With Source: Database, the sub-workflow must be published. Otherwise the tool call fails with
Workflow is not active and cannot be executed, and per the Call n8n Workflow Tool docs that text comes back to the agent as the tool result, where it's easy to miss. - The parent can't start the sub-workflow at all. Per the trigger docs, a sub-workflow with errors can't be triggered. Open it and fix any node in an error state, the memory node included.
- The sub-agent answers but doesn't remember. Open the call node and follow View sub-execution (per the trigger docs) to check that
sessionIdarrived, isn't empty, and is the same value on every turn. - Two conversations see each other's sub-agent history. A static test key is still set. The common issues page suggests a static key like
my_test_sessiononly for testing. - Memory is lost or mixed in production with several workers. Simple Memory doesn't work in active production workflows in queue mode. Use a database-backed memory node.
Common questions
How do I give an n8n sub-agent the same chat memory as the main agent?
Add a sessionId input to the sub-workflow's Execute Sub-workflow Trigger, fill it from the Chat Trigger's sessionId with an expression in the Call n8n Workflow Tool, and set the sub-agent's memory Session Key to {{ $json.sessionId }} on the same memory backend and table.
Should the sub-agent use exactly the same Session Key?
Only if it should read and add to the main conversation. Per n8n's docs, memory nodes share one memory instance unless you set different session IDs, so a derived key like <sessionId>:colors gives the sub-agent its own history.
Does the AI Agent Tool node need the session passed in? No input passing is needed, because it runs in the same workflow as the Chat Trigger. Its docs page doesn't document a memory setting, so check your version.
Does a shared session ID give agents memory across chats? No. It shares one conversation. For facts that follow a person into new chats you need memory keyed by the person, such as an End User ID (Step 7).
Related pages
- Adding chat memory to an n8n agent with MemorySync
- n8n WhatsApp AI agent memory: which Session ID to use
- n8n Postgres Chat Memory: fixing 'Got unexpected type: user'
Sources
- community.n8n.io/t/my-sub-agents-doesnt-have-chat-memory/111683 (opened 2025-05-06, auto-closed 2025-08-04; example workflow and transcript in the reply; read 2026-10-29)
- n8n docs: Execute Sub-workflow Trigger, Call n8n Workflow Tool, AI Agent Tool, Simple Memory and its common issues, Postgres Chat Memory,
$fromAI(), expression reference for other nodes' output (fetched 2026-10-29) - MemorySync n8n guide: docs.memorysync.io/guides/n8n (fetched 2026-10-29)
Try it
For an overview of MemorySync, see the MemorySync homepage.
Next step: read the MemorySync n8n guide, then see MemorySync. Founding offer: use code FOUNDING30 for 30% off Starter for your first 3 months (Settings → Billing).
About the author
- Building MemorySync (memorysync.io) — persistent memory infrastructure for AI agents, Cursor, and Claude Code.
Comments
Join the discussionNo comments yet. Be the first to comment.
