n8n - ✅(Solved) Fix RabbitMQ Node: Routing key expression evaluated only once for multi-item batches in exchange mode [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
n8n-io/n8n#28525Fetched 2026-04-16 07:05:15
View on GitHub
Comments
1
Participants
2
Timeline
5
Reactions
0
Timeline (top)
commented ×1cross-referenced ×1labeled ×1mentioned ×1

Error Message

  • error: all

Root Cause

In packages/nodes-base/nodes/RabbitMQ/RabbitMQ.node.ts, the routingKey parameter was fetched outside the per-item loop with a hardcoded index of 0:

const routingKey = this.getNodeParameter('routingKey', 0) as string;
// ...
for (let i = 0; i < items.length; i++) {
  // routingKey is the same for every item
  channel.publish(exchange, routingKey, Buffer.from(message), { ... });
}

Other per-item parameters like message and options.headers are correctly evaluated inside the loop with index i.

Fix Action

Fixed

PR fix notes

PR #28526: fix(RabbitMQ Node): Fix RabbitMQ routing key resolution

Description (problem / solution / changelog)

Summary

The RabbitMQ node's routingKey parameter was evaluated once (at item index 0) and reused for every item in a batch when publishing to an exchange. This meant dynamic expressions like ={{ $json._routingKey }} only resolved to the first item's value — all subsequent items were silently published with the wrong routing key.

The fix moves getNodeParameter('routingKey', i) inside the per-item loop so each item's routing key expression is evaluated independently, matching the existing behavior of message and options.headers.

Before: 3 items with distinct routing keys all published under the first item's key.

itemexpression valueAMQP routing key
0test.dynamic.alphatest.dynamic.alpha
1test.dynamic.betatest.dynamic.alpha
2test.dynamic.gammatest.dynamic.alpha

After: each item publishes with its own evaluated routing key.

Related Linear tickets, Github issues, and Community forum posts

https://github.com/n8n-io/n8n/issues/28525

fixes #28525

Review / Merge checklist

  • I have seen this code, I have run this code, and I take responsibility for this code.
  • PR title and summary are descriptive. (conventions)
  • Docs updated or follow-up ticket created.
  • Tests included.

Changed files

  • packages/nodes-base/nodes/RabbitMQ/RabbitMQ.node.ts (modified, +2/-1)
  • packages/nodes-base/nodes/RabbitMQ/test/RabbitMQ.node.test.ts (added, +161/-0)

Code Example

const routingKey = this.getNodeParameter('routingKey', 0) as string;
// ...
for (let i = 0; i < items.length; i++) {
  // routingKey is the same for every item
  channel.publish(exchange, routingKey, Buffer.from(message), { ... });
}

---

[
     { "seq": 1, "_routingKey": "test.dynamic.alpha" },
     { "seq": 2, "_routingKey": "test.dynamic.beta" },
     { "seq": 3, "_routingKey": "test.dynamic.gamma" }
   ]
RAW_BUFFERClick to expand / collapse

Bug Description

Describe the bug

When the RabbitMQ node (v1.1) is configured in exchange mode with a dynamic routingKey expression (e.g. ={{ $json._routingKey }}), the expression is evaluated only once using the first input item. All subsequent items in the batch are published with that same routing key, even though each item's expression would resolve to a different value.

The message body is correctly evaluated per-item — only the routing key is affected.

Actual behavior

All 3 messages are published with the first item's routing key:

itemexpression valueAMQP routing key
0test.dynamic.alphatest.dynamic.alpha
1test.dynamic.betatest.dynamic.alpha ❌
2test.dynamic.gammatest.dynamic.alpha ❌

Root cause

In packages/nodes-base/nodes/RabbitMQ/RabbitMQ.node.ts, the routingKey parameter was fetched outside the per-item loop with a hardcoded index of 0:

const routingKey = this.getNodeParameter('routingKey', 0) as string;
// ...
for (let i = 0; i < items.length; i++) {
  // routingKey is the same for every item
  channel.publish(exchange, routingKey, Buffer.from(message), { ... });
}

Other per-item parameters like message and options.headers are correctly evaluated inside the loop with index i.

Environment

  • n8n version: 1.91.3 and earlier
  • Node: RabbitMQ v1.1
  • Mode: Exchange (topic, direct, headers, fanout — all affected)

To Reproduce

  1. Create a Code node that outputs 3 items with distinct routing keys:
    [
      { "seq": 1, "_routingKey": "test.dynamic.alpha" },
      { "seq": 2, "_routingKey": "test.dynamic.beta" },
      { "seq": 3, "_routingKey": "test.dynamic.gamma" }
    ]
  2. Connect to a RabbitMQ node configured in exchange mode with:
    • Exchange: pipeline.bus (topic type)
    • Routing Key: ={{ $json._routingKey }}
    • Send Input Data: enabled
  3. Execute the workflow.

Expected behavior

Each message should be published with its own evaluated routing key:

itemexpression valueAMQP routing key
0test.dynamic.alphatest.dynamic.alpha
1test.dynamic.betatest.dynamic.beta
2test.dynamic.gammatest.dynamic.gamma

Debug Info

Debug info

core

  • n8nVersion: 2.11.4
  • platform: docker (self-hosted)
  • nodeJsVersion: 24.13.1
  • nodeEnv: production
  • database: sqlite
  • executionMode: regular
  • concurrency: -1
  • license: community
  • consumerId: unknown

storage

  • success: all
  • error: all
  • progress: false
  • manual: true
  • binaryMode: memory

pruning

  • enabled: true
  • maxAge: 336 hours
  • maxCount: 10000 executions

client

  • userAgent: mozilla/5.0 (macintosh; intel mac os x 10_15_7) applewebkit/537.36 (khtml, like gecko) chrome/146.0.0.0 safari/537.36
  • isTouchDevice: false

Generated at: 2026-04-15T11:49:45.925Z

Operating System

Alpine Linux v3.23.3

n8n Version

2.11.4

Node.js Version

24.13.1

Database

SQLite (default)

Execution mode

main (default)

Hosting

self hosted

extent analysis

TL;DR

The issue can be fixed by moving the routingKey evaluation inside the per-item loop to correctly evaluate the dynamic routing key expression for each item.

Guidance

  • The root cause of the issue is the routingKey parameter being fetched outside the per-item loop with a hardcoded index of 0, causing all items to be published with the same routing key.
  • To fix this, the routingKey evaluation should be moved inside the loop, using the current item's index i to correctly evaluate the dynamic routing key expression for each item.
  • The corrected code should look similar to this:
for (let i = 0; i < items.length; i++) {
  const routingKey = this.getNodeParameter('routingKey', i) as string;
  channel.publish(exchange, routingKey, Buffer.from(message), { ... });
}
  • This change will ensure that each item is published with its own evaluated routing key.

Example

The provided code snippet in the issue already shows the problematic code. The corrected code should be similar to the one provided in the guidance section.

Notes

This fix assumes that the getNodeParameter method correctly evaluates the dynamic routing key expression for each item. If this method has any issues, additional debugging may be required.

Recommendation

Apply the workaround by moving the routingKey evaluation inside the per-item loop, as this will correctly evaluate the dynamic routing key expression for each item.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Each message should be published with its own evaluated routing key:

itemexpression valueAMQP routing key
0test.dynamic.alphatest.dynamic.alpha
1test.dynamic.betatest.dynamic.beta
2test.dynamic.gammatest.dynamic.gamma

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING