| |

n8n AWS SNS 400 Bad Request With Empty Error? The 2026 Fix

n8n’s AWS SNS node failing with 400 and an empty message? It’s the GET request, not the 256 KB limit. Here’s how to fix large SOC alerts.

Your n8n workflow has been pushing critical alerts to AWS SNS for months, and suddenly one execution dies with “Bad request – please check your parameters” and a full message of just 400 – “”. No error code from AWS, no hint about which parameter, nothing in the body. If the alert that failed was bigger than usual, you are almost certainly looking at the same problem we were.

What does the empty 400 from the n8n AWS SNS node actually mean?

The important detail is the empty string. When SNS rejects a publish because of something it understands, like a bad topic ARN or a subject that is too long, it answers with an XML error body that names the problem, such as InvalidParameter. An empty body means the request never got far enough to be parsed as an SNS call. Something upstream of the SNS logic refused it.

That points straight at how the request is built. The n8n AWS SNS node (type n8n-nodes-base.awsSns) does not send a POST with a body. It sends the Publish action as an HTTP GET, with the topic, subject and message URL-encoded into the query string. We checked this in the current n8n source on the master branch, and it is still the case at the time of writing, including the 2.4x release line.

So your whole alert, every table row and every summary, becomes part of the URL. URL-encoding also inflates it, because every space, pipe, colon and slash turns into a three-character escape. A description that looks moderately sized in the n8n editor turns into a URL many times longer than any sane server accepts, and the request gets bounced with no explanation.

Symptom Likely cause Quick check
400 with empty message, only on some alerts Message too long for a GET query string Re-run with the message cut to 1,500 characters
400 with InvalidParameter in the body SNS-level validation, for example a subject of 100+ characters or a bad ARN Read the XML error text in the node output
403 AuthorizationError IAM policy missing sns:Publish on the topic Test the same credential with a tiny static message
Fails on every alert, even small ones Credential, region or topic problem, not size Publish “test” from the node with no expressions

Why “it is nowhere near 256 KB” is the wrong mental model

This is the wrong turn almost everyone takes, and we took it too. The SNS documentation says a message can be up to 256 KiB by default. Your alert is a few thousand lines of markdown at most, so size gets ruled out in the first five minutes and the investigation moves on to IAM, regions and expression syntax.

The 256 KiB figure is real, but it is the limit on the message once SNS has received it. It says nothing about how big a URL the endpoint will accept before SNS even sees the request. AWS’s own guidance for Query API services is explicit here. GET requests are bounded by URL length, and for requests that need larger sizes you must use POST. The n8n node never uses POST for Publish, so for this node the practical limit is the URL, not the message.

What made it sneaky is that the payloads was growing slowly. The detection side had started aggregating related findings into one alert, which is a good change for analyst fatigue. But each aggregated alert carried every event ID, every affected endpoint and a separate summary per finding. Small alerts kept working, so the workflow looked healthy right up until one crossed the line.

📌 Official Resource: AWS documents that Query API GET requests are limited by URL size and that larger requests must use POST. Visit Official Website

How to confirm the payload size is the problem in two minutes

Don’t start rewriting the workflow until you have proven the cause. The fastest proof is to shrink the message and see if the exact same node, credential and topic suddenly work. If they do, you have eliminated permissions, region and topic configuration in one step.

  1. Open the failing execution and pin the trigger data, so you can replay the same oversized alert.
  2. In the SNS node’s Message field, temporarily replace the Description expression with a sliced version (below).
  3. Click Execute step. If you get a MessageId back, size is confirmed.
  4. Optionally, add a Code node to measure the encoded length, so you know how much headroom you have.

This expression takes the alert description, serialises it safely, and keeps only the first 1,500 characters. It is a diagnostic, not the final fix.

{{ JSON.stringify($node["TheHive Trigger"].json.body.object.description).slice(0, 1500) }}

To see how big the request really gets, measure the URL-encoded length rather than the raw length. This one-liner in a Code node returns both numbers side by side, and the gap between them is usually the surprise.

const d = $('TheHive Trigger').first().json.body.object.description || '';
return [{ json: { raw: d.length, encoded: encodeURIComponent(d).length } }];

💬 “The funniest part came afterwards. When we exported the workflow, the firewall branch of the very same workflow already had a hardcoded Description saying the details were too long for the email and to check the case tool. Somebody had hit this exact wall before, patched around it for one alert source, and never wrote down why. Nobody revisited it when a second source started producing big alerts.”

Which fix should you use: truncate, POST, or an SDK?

Once the cause is clear there are three sensible fixes, and they differ mainly in how much of the alert you want in the notification. Be honest about who reads the notification. If it lands in an email or a chat channel, a human will read the title and the first few fields and then click through to the case anyway. Nobody reads twenty-four AI summaries in an email.

Option Effort Keeps full payload Best for
Truncate the description in the SNS node Minutes No, links to the case instead Human-read email or chat notifications
HTTP Request node doing a signed POST to SNS Around 30 minutes Yes, up to the topic’s size limit Machine consumers that need every field
Small Lambda or script using the AWS SDK An hour or more Yes Teams already routing alerts through Lambda
Raise the topic’s MaximumMessageSize Minutes Does not help on its own Only useful together with a POST-based publisher

The last row matters, because it is a tempting red herring. AWS now lets you raise a topic’s MaximumMessageSize attribute up to 1 MiB, from the default of 256 KiB. That changes what SNS will accept once the request arrives. It does nothing for a GET request that is rejected before SNS reads it, so on its own it will not fix the n8n node.

📌 Official Resource: The SNS Publish API reference covers message size, the MaximumMessageSize attribute and the subject rules. Visit Official Website

How to truncate SNS alert messages cleanly in n8n

For most SOC notification flows, truncation is the right answer. The important part is to truncate visibly. A silently cut message is worse than a failed one, because an analyst reading it has no idea anything is missing. Always append a marker that tells them to open the case.

We also recommend moving the message building out of one giant inline expression and into a Code node just before the SNS node. Long chains of .replace() calls stuffed inside a Message field are hard to read and very hard to debug at 2am. JSON.stringify on a real object gives you valid JSON automatically, with no hand-escaping.

const o = $('TheHive Trigger').first().json.body.object;
const LIMIT = 3000;
let desc = o.description || '';
if (desc.length > LIMIT) {
desc = desc.slice(0, LIMIT) + '\n... [truncated - full details in the case]';
}
const message = JSON.stringify({
Title: o.title,
Type: o.type,
Description: desc,
SourceRef: o.sourceRef
});
const subject = ('Case tool - new critical alert from ' + o.source).slice(0, 99);
return [{ json: { subject, message, encodedLength: encodeURIComponent(message).length } }];

This code builds the message as an object, caps the description at 3,000 characters with a visible truncation marker, and keeps the subject under the 100-character limit SNS enforces. It also outputs the encoded length, so you can watch it in executions. In the SNS node, set Subject to {{ $json.subject }} and Message to {{ $json.message }}.

If you want to keep more signal in the same budget, cut at a known section rather than at a character count. In aggregated cloud findings, the per-finding AI summaries and the list of console links usually make up more than half the payload. They add little value in a notification, because the analyst will open the case to see them anyway.

How to publish the full payload with a POST instead

If something downstream parses the SNS message and genuinely needs every field, stop using the SNS node and send the request yourself with the HTTP Request node. n8n’s AWS credential can sign arbitrary requests when you pick it as a predefined credential type. That means you keep the same IAM user or role and just change the transport.

  • Method: POST, so parameters travel in the body and never touch the URL.
  • URL: https://sns.YOUR-REGION.amazonaws.com/, matching the topic’s region, because SNS only publishes to topics in the same region as the endpoint.
  • Authentication: Predefined Credential Type, then your existing AWS credential, so the request is signed with SigV4.
  • Body: Form URL-encoded, with the fields shown below.
Action = Publish
Version = 2010-03-31
TopicArn = arn:aws:sns:YOUR-REGION:111122223333:soc-critical-alerts
Subject = {{ $json.subject }}
Message = {{ $json.message }}

These are the same parameters the SNS node sends, plus the API version, just moved from the query string into the request body. A successful call returns an XML PublishResponse with a MessageId. Make sure your error handling checks for that, rather than treating any 200 as success. If you later need payloads bigger than 256 KiB, this is the setup where raising the topic’s MaximumMessageSize actually starts to help, though you should check that your subscription types support larger messages first.

Frequently Asked Questions

Why does the n8n AWS SNS node return 400 with an empty message?

Usually because the request was rejected before SNS parsed it, and the node sends everything in a GET query string. Very large messages make the URL too long, and the endpoint refuses it without an SNS error body.

Isn’t the SNS message limit 256 KB?

Yes, by default, and topics can now be raised to 1 MiB. But that limit applies to the message SNS receives, not to the URL, and a GET-based publisher hits the URL limit long before the message limit.

Does the n8n SNS node support POST?

Not for Publish. In the current source it builds a GET request with the parameters in the query string, so for large payloads use the HTTP Request node with your AWS credential.

How long can the SNS subject be?

Under 100 characters, with no line breaks or control characters. A subject that breaks these rules returns a proper error rather than an empty 400, which helps you tell the two problems apart.

Will raising MaximumMessageSize fix the n8n error?

Not by itself, because the GET request is rejected before the topic’s size setting is ever checked. It only helps once you publish with POST, through the HTTP Request node or an SDK.

How much of an alert should go into an SNS notification?

Enough for triage: title, severity, source, key entities and a link to the case. Everything else belongs in the case tool, and truncated messages should say so explicitly.


Final Thoughts

The bug here was not really in n8n or in SNS. It was a transport decision nobody revisited. A node that sends everything as a GET works perfectly for years, as long as the payloads stay small. The day detection engineering starts aggregating findings, which is the right call for analyst sanity, the alerting path quietly stops delivering exactly the alerts that matter most. The earlier workaround on another branch shows the team had already been bitten once and treated it as a one-off.

The broader principle is to treat notification payloads as a budget, and to make your alerting fail loudly. A notification should carry what an analyst needs to decide whether to open the case, and it should say clearly when it has been cut. And any node that can fail on content size should have its errors routed somewhere visible, rather than dying in an execution log nobody checks.

One thing you can do today: find every SNS node in your n8n instance, add the encoded-length output from the Code node above, and look at your largest recent alert. If it is anywhere near the size that failed for us, move that flow to truncation or to a signed POST before the next big aggregated alert finds it for you.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *