Fix SNS Message Delivery Failures in AWS (SQS, Lambda, HTTP, Filters, DLQs)

Your SNS topic is receiving publishes. CloudWatch confirms messages are going in. But one or more subscribers are getting nothing. SNS does not surface delivery failures loudly by default, so the gap between “published” and “delivered” can stay invisible for a long time. This page covers every common cause in order of likelihood: missing SQS queue policies, absent Lambda permissions, HTTP endpoint issues, filter policy mismatches, unconfirmed subscriptions, and logging blind spots.

Simple explanation

SNS is a pub/sub service: publishers send a message to a topic, and SNS attempts to push copies to every matching subscriber. The key word is attempts.

“Published” and “delivered” are different states. A message can be published to a topic successfully while every single delivery to subscribers fails. SNS’s publish API returns success the moment it accepts the message, before any subscriber has received it.

Analogy

Think of SNS like a post office drop box. When you drop a letter in the slot, the post office accepts it immediately — that is “published.” But delivery only succeeds if the address is valid, the mailbox exists, and the recipient hasn’t blocked incoming mail. The drop box doesn’t know any of that when it accepts your envelope. SNS works the same way: it accepts your message without verifying that any subscriber can actually receive it.

Delivery failures can happen at multiple points:

  • Subscription level — the subscription is not confirmed, or is misconfigured
  • Permission level — the endpoint (SQS queue, Lambda function) has not granted SNS permission to write to it
  • Filtering level — the message does not match the subscription’s filter policy and is silently skipped
  • Endpoint level — the HTTP endpoint is unreachable, returning errors, or has not handled SNS’s confirmation request
  • Capacity level — a Lambda function is throttled and cannot accept the invocation

Different endpoint types fail in different ways. SQS failures are almost always permission-related. Lambda failures are usually permission or throttling. HTTP/HTTPS failures are often confirmation, connectivity, or response-code issues.

How SNS delivery works

Understanding the delivery flow makes it easier to identify where a failure is happening.

Analogy

SNS fan-out works like a radio broadcast tower. The tower transmits a signal to everyone tuned to that frequency. But each radio needs its own antenna, working batteries, and the right frequency set. If one radio is broken, the others still receive the broadcast. SNS is the tower: one publish reaches many subscribers independently, and a problem with one subscriber does not affect the others.

  1. Publish — a producer calls sns:Publish on a topic. SNS accepts the message and returns a MessageId. This is success from the publisher’s perspective.
  2. Fan-out — SNS evaluates every active subscription on the topic. Each subscription is processed independently.
  3. Filter evaluation — if a subscription has a filter policy, SNS checks whether the message attributes (or message body) match. Messages that do not match are skipped for that subscription. This is not an error.
  4. Delivery attempt — for matching subscriptions, SNS pushes the message to the endpoint. How this works depends on the endpoint type:
    • SQS: SNS calls sqs:SendMessage on the queue. Requires a queue resource policy allowing this.
    • Lambda: SNS calls lambda:InvokeFunction. Requires a Lambda resource-based policy allowing this.
    • HTTP/HTTPS: SNS POSTs the message as JSON to the URL. The subscription must be confirmed and the endpoint must be reachable.
    • Email/Email-JSON: SNS sends an email. Requires manual confirmation. Not suitable for automation.
  5. Retry or fail — if delivery fails, SNS retries according to the delivery policy. After all retries are exhausted, the message goes to the subscription DLQ (if configured) or is permanently discarded.

Because SNS fans out to each subscription independently, one subscription can fail while others succeed. Topic-level metrics are aggregates, so a failure in one subscription can be diluted by successes in others. This is why per-subscription visibility (delivery logs, DLQs) matters.

See the SNS messaging model for a deeper look at topics, subscriptions, and message attributes.

Start here: the fastest way to diagnose SNS delivery failures

Where to start

Check NumberOfNotificationsFailed and NumberOfNotificationsFilteredOut in CloudWatch first. These two numbers will immediately tell you whether the problem is a permission/endpoint failure or a filter policy mismatch. Everything below builds on that answer.

Work through these checks in order. Each one either confirms the problem or rules it out.

1. Are messages being published? Check NumberOfMessagesPublished in CloudWatch for the topic. If this is zero, the problem is upstream of SNS — the publisher is not calling sns:Publish successfully.

2. Are deliveries failing or being filtered?

  • NumberOfNotificationsFailed > 0 means delivery is failing (permission, connectivity, or endpoint error)
  • NumberOfNotificationsFilteredOut > 0 means filter policies are blocking messages
  • Both zero with NumberOfMessagesPublished > 0 means something else — check subscription confirmation status

3. Is the subscription confirmed?

aws sns list-subscriptions-by-topic \
  --topic-arn arn:aws:sns:us-east-1:111122223333:my-topic

Look at the SubscriptionArn field. If it shows PendingConfirmation, the subscription has not been confirmed. For HTTP/HTTPS and email subscriptions, SNS sends a confirmation request that must be actioned before delivery begins.

4. What is the endpoint type?

  • SQS — check the SQS queue resource policy first
  • Lambda — check the Lambda resource-based policy, then check for throttling
  • HTTP/HTTPS — check confirmation status, endpoint reachability, and response codes
  • Email — verify the recipient confirmed the subscription manually

5. Is delivery status logging enabled? If not, you are working blind. SNS delivery logs in CloudWatch Logs give you per-delivery results with failure reasons. Enable it before continuing if it is off.

6. Is a DLQ configured? Check each subscription’s RedrivePolicy attribute. If no DLQ is set, failed messages after max retries are permanently gone with no record of what failed.

CloudWatch metrics: what they tell you and how to read them together

SNS publishes CloudWatch metrics at the topic level. These are your first stop — they tell you the scale and type of the problem.

aws cloudwatch get-metric-statistics \
  --namespace AWS/SNS \
  --metric-name NumberOfNotificationsFailed \
  --dimensions Name=TopicName,Value=my-topic \
  --start-time 2026-05-12T00:00:00Z \
  --end-time 2026-05-13T00:00:00Z \
  --period 3600 \
  --statistics Sum
MetricWhat it meansWhat a bad value usually indicates
NumberOfMessagesPublishedMessages SNS accepted from publishersZero = publisher issue, not SNS
NumberOfNotificationsDeliveredSuccessful deliveries to subscribersLower than expected = some subscriptions failing
NumberOfNotificationsFailedDelivery attempts that failed after all retriesPermission errors, unreachable endpoints
NumberOfNotificationsFilteredOutMessages skipped due to filter policy mismatchFilter policy too narrow, or publisher omitting required attributes
NumberOfNotificationsFilteredOut-InvalidAttributesMessages filtered because attributes were malformedPublisher using wrong attribute format

How to interpret combinations:

  • Published = 100, Delivered = 0, Failed = 100 — every delivery is failing for every subscription. Almost always a permission error (missing SQS policy or Lambda permission).
  • Published = 100, Delivered = 0, FilteredOut = 100 — filter policies are blocking all messages. The publisher is not sending the attributes the subscriptions require.
  • Published = 100, Delivered = 50, Failed = 50 — some subscriptions are working, some are failing. Check subscriptions individually: one endpoint is misconfigured.
  • Published = 100, Delivered = 100, Failed = 0 — metrics look healthy but a subscriber still is not getting messages. Check subscription confirmation status and verify FilterPolicyScope is what you expect.
Topic metrics are aggregates

These numbers are totals across all subscriptions on the topic. If you have 5 subscriptions and 1 is broken, the failure count will be 20% of NumberOfMessagesPublished — easy to miss without looking at the ratio. For per-subscription detail, enable delivery status logging.

Common root causes by endpoint type

SNS to SQS delivery failures#

The most common cause is straightforward: the SQS queue does not have a resource policy allowing SNS to send messages to it.

Silent failure by design

SNS lets you create an SNS-to-SQS subscription without the required queue policy. The subscription shows as confirmed and active. Every message published to the topic fails to deliver. No error is shown to the publisher. This is the most common cause of “messages published, queue empty” and it is completely invisible until you check the queue policy manually.

Check whether the queue has a policy:

aws sqs get-queue-attributes \
  --queue-url https://sqs.us-east-1.amazonaws.com/111122223333/my-queue \
  --attribute-names Policy

If Policy is empty or missing an sns.amazonaws.com statement, add it:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "Service": "sns.amazonaws.com"
    },
    "Action": "sqs:SendMessage",
    "Resource": "arn:aws:sqs:us-east-1:111122223333:my-queue",
    "Condition": {
      "ArnEquals": {
        "aws:SourceArn": "arn:aws:sns:us-east-1:111122223333:my-topic"
      }
    }
  }]
}

The Condition restricts the permission to the specific SNS topic. Without it, any SNS topic could send to this queue.

Apply the policy:

aws sqs set-queue-attributes \
  --queue-url https://sqs.us-east-1.amazonaws.com/111122223333/my-queue \
  --attributes Policy='{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"sns.amazonaws.com"},"Action":"sqs:SendMessage","Resource":"arn:aws:sqs:us-east-1:111122223333:my-queue","Condition":{"ArnEquals":{"aws:SourceArn":"arn:aws:sns:us-east-1:111122223333:my-topic"}}}]}'

KMS-encrypted queues. If the SQS queue uses server-side encryption with a customer-managed KMS key, SNS also needs kms:GenerateDataKey and kms:Decrypt permissions on that key. Add the sns.amazonaws.com service principal to the KMS key policy. Queues using the AWS-managed aws/sqs key do not require this.

Cross-account subscriptions. When the SNS topic and the SQS queue are in different AWS accounts, both sides need to grant access: the SQS queue policy must allow the specific topic ARN from the other account, and the SNS topic policy must allow the other account’s queue to subscribe. See IAM policy structure for how resource-based policies work across accounts.

Test end-to-end after adding the policy:

aws sns publish \
  --topic-arn arn:aws:sns:us-east-1:111122223333:my-topic \
  --message "policy-test"

aws sqs receive-message \
  --queue-url https://sqs.us-east-1.amazonaws.com/111122223333/my-queue

If the message appears in SQS within a few seconds, the policy is correct. If the queue is still empty, check whether the subscription’s filter policy requires attributes you did not include in the test publish.

SNS to Lambda delivery failures#

For SNS to invoke a Lambda function, the function needs a resource-based policy granting lambda:InvokeFunction to sns.amazonaws.com. This is separate from the Lambda execution role — it is a permission on the function itself that controls which services can trigger it.

Same silent failure as SQS

You can create an SNS-to-Lambda subscription without the Lambda resource policy. The subscription confirms successfully. SNS attempts delivery, gets an access denied response, and silently retries until the message is gone. Add aws lambda get-policy —function-name my-function to your setup checklist so this is never missed.

Check the current resource policy:

aws lambda get-policy --function-name my-function

If the command returns ResourceNotFoundException or the output does not include an SNS statement, add it:

aws lambda add-permission \
  --function-name my-function \
  --statement-id sns-invoke \
  --action lambda:InvokeFunction \
  --principal sns.amazonaws.com \
  --source-arn arn:aws:sns:us-east-1:111122223333:my-topic

The --source-arn parameter scopes the permission to the specific SNS topic. Without it, any SNS topic could invoke the function.

Lambda throttling. If the function is at its concurrency limit, SNS cannot invoke it. SNS retries throttled Lambda invocations up to 3 times with a 1-second delay between attempts. If throttling persists across all retries, messages go to the DLQ (if configured) or are discarded.

Check for throttles:

aws cloudwatch get-metric-statistics \
  --namespace AWS/Lambda \
  --metric-name Throttles \
  --dimensions Name=FunctionName,Value=my-function \
  --start-time 2026-05-12T00:00:00Z \
  --end-time 2026-05-13T00:00:00Z \
  --period 3600 \
  --statistics Sum

If throttles are frequent, raise the function’s reserved concurrency or reduce execution duration. See debugging Lambda failures for a deeper look at Lambda-side issues once you have confirmed SNS is delivering correctly.

Cross-account Lambda. When the SNS topic is in Account A and the Lambda function is in Account B, include --source-account to prevent confused-deputy privilege escalation:

aws lambda add-permission \
  --function-name my-function \
  --statement-id sns-cross-account-invoke \
  --action lambda:InvokeFunction \
  --principal sns.amazonaws.com \
  --source-arn arn:aws:sns:us-east-1:111122223333:my-topic \
  --source-account 111122223333

For more on how SNS triggers Lambda and how event source configuration works, see AWS Lambda event triggers explained.

SNS to HTTP/HTTPS delivery failures#

HTTP/HTTPS endpoints are the trickiest to debug because failures can happen at three distinct stages: confirmation, reachability, and response codes.

Subscription confirmation is required

When you create an HTTP/HTTPS subscription, SNS immediately sends a SubscriptionConfirmation POST to the endpoint. The endpoint must receive this, extract the SubscribeURL from the JSON body, and make a GET request to that URL. Until this happens, the subscription stays in PendingConfirmation and SNS delivers nothing. This is a common integration pitfall: the endpoint handles normal SNS POSTs but never handles the confirmation format, so the subscription never activates.

Check subscription status:

aws sns list-subscriptions-by-topic \
  --topic-arn arn:aws:sns:us-east-1:111122223333:my-topic \
  --query 'Subscriptions[?Protocol==`https`]'

Endpoint reachability. The endpoint URL must be publicly reachable from AWS SNS servers. SNS cannot reach endpoints behind a VPN, a private network, or a firewall that blocks AWS IP ranges. If the endpoint needs to be internal, consider routing through SNS to SQS to an internal consumer instead of a direct HTTP subscription.

Response codes. SNS considers a delivery successful only if the endpoint returns a 2xx HTTP response within the timeout window. Anything else — including 3xx redirects, 4xx client errors, and 5xx server errors — is treated as a failure and triggers a retry.

Retry and delivery policy. SNS uses a delivery policy to control retry behavior for HTTP/HTTPS. The default policy retries with exponential backoff over several hours. You can customize the retry count, minimum delay, maximum delay, and backoff function per subscription. After all retries are exhausted, the message goes to the subscription DLQ (if configured) or is permanently discarded.

Which failures are retried:

  • 5xx server errors — retried, as the server-side issue may resolve
  • 4xx client errors — retried, as SNS does not distinguish client versus server fault
  • Connection timeouts — retried
  • DNS resolution failures or TCP connection refused — retried up to the policy limit

There is no built-in way to tell SNS to stop retrying on specific status codes. If you need to prevent retries for a specific endpoint, delete the subscription.

Filter policies blocking messages#

Analogy

A filter policy works like a club with a dress code. The club (SNS subscription) only lets in guests (messages) that meet the requirements. Guests who do not meet the criteria are turned away at the door — quietly, with no incident report. They are just not there. That is why a filtered-out message does not appear in failure metrics: it was never rejected as a failure, it was simply never admitted.

A filter policy is a JSON document attached to a subscription. SNS only delivers a message to that subscription if the message’s attributes (or body) match the policy. Non-matching messages are silently skipped and appear in NumberOfNotificationsFilteredOut, not NumberOfNotificationsFailed.

Check a subscription’s filter policy:

aws sns get-subscription-attributes \
  --subscription-arn arn:aws:sns:us-east-1:111122223333:my-topic:abc-123 \
  --query 'Attributes.{FilterPolicy:FilterPolicy,FilterPolicyScope:FilterPolicyScope}'

FilterPolicy vs FilterPolicyScope. These two attributes work together and are easy to confuse:

  • FilterPolicy — the JSON matching rules (which attribute values to allow)
  • FilterPolicyScope — where to apply the rules: MessageAttributes (default) or MessageBody

If FilterPolicyScope is MessageAttributes (the default), the filter policy matches against the message’s MessageAttributes field. If FilterPolicyScope is MessageBody, it matches against the JSON structure of the message body itself.

The most common mistake: the filter policy is scoped to MessageAttributes but the publisher is embedding routing data in the message body JSON. The filter never matches because it is looking in the wrong place.

If the filter policy requires:

{ "event-type": ["order-placed", "order-updated"] }

And FilterPolicyScope is MessageAttributes, the publisher must include the attribute explicitly:

aws sns publish \
  --topic-arn arn:aws:sns:us-east-1:111122223333:my-topic \
  --message '{"orderId": "12345"}' \
  --message-attributes '{"event-type":{"DataType":"String","StringValue":"order-placed"}}'

Publishing without the event-type attribute, or with a value not listed in the policy, results in the message being filtered out for this subscription. Confirm this with NumberOfNotificationsFilteredOut in CloudWatch.

Unconfirmed or misconfigured subscriptions#

A subscription can appear active in the console but receive no messages for reasons beyond permissions and filters.

Pending confirmation. HTTP/HTTPS and email subscriptions require confirmation before messages are delivered. The SubscriptionArn field in list-subscriptions-by-topic output shows PendingConfirmation for unconfirmed subscriptions. SQS and Lambda subscriptions confirm automatically.

Email subscription limitations. Email subscriptions require a human to click a confirmation link. Once confirmed, delivery is best-effort with no retry guarantees and no DLQ support. Never use email subscriptions in automated pipelines — they are for human notifications only.

Subscription ARN drift. If you deleted and recreated an endpoint (SQS queue, Lambda function, or HTTP URL) without updating the subscription, the subscription may still point to the old endpoint ARN. List subscriptions and confirm the endpoint ARN matches your current infrastructure.

Delivery status logging: how to see what SNS is actually doing

Topic-level CloudWatch metrics tell you how many deliveries failed. Delivery status logs tell you which ones and why.

SNS can log every delivery attempt to CloudWatch Logs. Each log entry includes the subscription ARN, the endpoint, the delivery status (SUCCESS or FAILURE), the failure reason, and the number of retries attempted.

Without these logs, you are limited to aggregate topic metrics and have no way to identify which specific subscription or endpoint is failing.

Enable this before your production incident, not after

Failed messages that SNS discarded before logging was enabled are unrecoverable. There is no log to look at, no DLQ to inspect, nothing. Logging has minimal cost impact and provides the fastest path to diagnosing intermittent or partial failures. Turn it on during infrastructure setup.

Enable delivery status logging.

SNS delivery logging is enabled per endpoint protocol type (SQS, Lambda, HTTP, etc.) and requires an IAM role that allows SNS to write to CloudWatch Logs. The role needs logs:CreateLogGroup, logs:CreateLogStream, and logs:PutLogEvents, with sns.amazonaws.com as the trusted principal.

Once the role exists, enable it on the topic per protocol:

# Enable SQS delivery logging (failure + sampled success)
aws sns set-topic-attributes \
  --topic-arn arn:aws:sns:us-east-1:111122223333:my-topic \
  --attribute-name SQSSuccessFeedbackRoleArn \
  --attribute-value arn:aws:iam::111122223333:role/sns-delivery-log-role

aws sns set-topic-attributes \
  --topic-arn arn:aws:sns:us-east-1:111122223333:my-topic \
  --attribute-name SQSFailureFeedbackRoleArn \
  --attribute-value arn:aws:iam::111122223333:role/sns-delivery-log-role

aws sns set-topic-attributes \
  --topic-arn arn:aws:sns:us-east-1:111122223333:my-topic \
  --attribute-name SQSSuccessFeedbackSampleRate \
  --attribute-value 100

Repeat the same pattern using Lambda, HTTP, and HTTPS prefixes for other endpoint types. Set SuccessFeedbackSampleRate to 100 during troubleshooting. In production, a lower sample rate (10 to 25) is usually sufficient to keep log volume manageable while retaining full failure logging.

Logs appear under /aws/sns/ in CloudWatch Logs and are queryable with CloudWatch Logs Insights.

See Amazon CloudWatch overview for how to set up log groups, metric filters, and alarms around SNS delivery failures.

Dead-letter queues: when failures stop being invisible

Analogy

A dead-letter queue is like the undeliverable mail office at a post office. When the carrier tries to deliver a letter multiple times and fails — address not found, no mailbox, recipient moved — the letter eventually ends up in a holding room. You can go look at it, read the address, and understand why it failed. Without that room, undeliverable letters are just thrown away. Without a DLQ, your failed SNS messages are discarded the same way: silently and permanently.

SNS subscription DLQ vs SQS queue DLQ — these are different things.

An SQS queue DLQ catches messages that a consumer failed to process after exceeding maxReceiveCount. An SNS subscription DLQ catches messages that SNS could not deliver to the endpoint at all. They solve different problems at different stages and must be configured separately.

What goes to the SNS subscription DLQ:

  • Messages SNS could not deliver to an SQS queue (permission errors after retries)
  • Messages SNS could not invoke Lambda for (throttling after retries)
  • Messages an HTTP/HTTPS endpoint kept rejecting (non-2xx after retries)

What does NOT go to the SNS subscription DLQ:

  • Messages filtered out by a filter policy (these are intentional, not failures)
  • Messages a consumer received from SQS but failed to process (that is the SQS-level DLQ’s responsibility)

Configure a DLQ on a subscription:

aws sns set-subscription-attributes \
  --subscription-arn arn:aws:sns:us-east-1:111122223333:my-topic:abc-123 \
  --attribute-name RedrivePolicy \
  --attribute-value '{"deadLetterTargetArn":"arn:aws:sqs:us-east-1:111122223333:my-topic-dlq"}'

The DLQ must be an SQS queue in the same AWS account and region as the subscription. The DLQ queue also needs a resource policy allowing SNS to send to it (the same sqs:SendMessage policy shown in the SNS to SQS section above).

Inspect failed messages in the DLQ:

aws sqs receive-message \
  --queue-url https://sqs.us-east-1.amazonaws.com/111122223333/my-topic-dlq \
  --attribute-names All \
  --message-attribute-names All

The message system attributes include DeliveryFailureCode and DeliveryFailureMessage, which explain specifically why SNS could not deliver (access denied, endpoint returned 500, Lambda throttled, etc.).

Practical workflow. When you find messages in a DLQ: fix the underlying cause (add the missing queue policy, fix the Lambda permission), then republish the messages from the DLQ to the original SNS topic or directly to the repaired endpoint.

When SNS is the right fit

If you are troubleshooting delivery failures, you have already committed to SNS. But it helps to understand whether the architecture is suited to your use case.

SNS is the right choice when you need to:

  • Notify multiple independent subscribers about the same event (fan-out): one publish, many receivers
  • Decouple a producer from its consumers in an event-driven architecture — the producer does not need to know which services are listening
  • Route messages selectively to different consumers based on message content using filter policies

SNS is not a message queue. It does not store messages for later processing and does not provide at-least-once delivery guarantees for all endpoint types. If you need durable message storage, guaranteed processing, or consumer-controlled polling, use SQS, often in combination with SNS.

SNS vs SQS: are you debugging the right service?

When troubleshooting message delivery issues, it helps to be clear about which service owns which failure.

SNS pushes; SQS stores. SNS actively delivers messages to subscribers the moment they are published. SQS stores messages in a queue until a consumer polls for them. If no consumer is polling an SQS queue, messages accumulate there — that is not an SNS delivery failure.

SymptomLikely causeService to investigate
No messages arriving in SQS queueMissing SQS resource policy, filter mismatch, or subscription misconfigurationSNS subscription + SQS resource policy
Messages in SQS but not processedConsumer not polling, visibility timeout, or consumer errorsSQS consumer / application
Lambda not receiving eventsMissing Lambda resource policy, or throttlingSNS subscription + Lambda
HTTP endpoint not receiving POSTsSubscription in PendingConfirmation, or endpoint unreachableSNS subscription + endpoint reachability

SNS to SQS is a common pattern. Publishing to an SNS topic and subscribing an SQS queue is the standard way to combine fan-out with durable storage. In this setup, delivery failures between SNS and SQS (the push half) are separate from processing failures inside SQS (the queue half). Diagnose each side independently.

See the full SNS vs SQS comparison for a complete breakdown of when to use each service and when to combine them.

Common mistakes

  1. Assuming “published” means “delivered” — SNS returns success when it accepts the message, before any delivery attempt. A successful publish API response does not guarantee any subscriber received the message.
  2. Missing the SQS queue resource policy — SNS lets you create an SNS-to-SQS subscription without the required queue policy. The subscription shows as confirmed but every message fails silently. This is the most common cause of empty SQS queues.
  3. Missing the Lambda invoke permission — same pattern as SQS. You can create the subscription without the Lambda resource-based policy. No error, no delivery, no indication anything is wrong.
  4. Publishing messages without the required filter policy attributes — if a subscription requires event-type: order-placed, a message published without that attribute is silently filtered out. It appears as NumberOfNotificationsFilteredOut, not a failure.
  5. Not enabling delivery status logging — topic-level metrics tell you something is wrong. Delivery logs tell you exactly what and where. Without logs during a production incident, you are diagnosing with no history.
  6. Not configuring DLQs before going to production — messages that fail before you add a DLQ cannot be recovered. Add DLQs during infrastructure setup, not after a message-loss incident.
  7. Using email subscriptions in automated systems — email subscriptions require manual confirmation, have no retry guarantees, and do not support DLQs. They are not appropriate for automated message processing.
  8. Forgetting subscription confirmation on HTTP endpoints — an HTTP/HTTPS subscription stays in PendingConfirmation and receives no messages until the endpoint handles SNS’s initial confirmation request. Easy to miss if the endpoint does not log unknown POST formats.
  9. Confusing SNS subscription DLQs with SQS queue DLQs — they capture different failure types at different stages and must be configured independently. A DLQ on the SQS queue does not help if SNS could not deliver to the queue in the first place.

Real scenario: SQS queue receiving zero messages from SNS

An order processing system publishes order events to an SNS topic. A downstream SQS queue is supposed to receive these events for processing, but the queue is consistently empty even though orders are being placed.

Step 1 — Confirm messages are being published:

aws cloudwatch get-metric-statistics \
  --namespace AWS/SNS \
  --metric-name NumberOfMessagesPublished \
  --dimensions Name=TopicName,Value=order-events \
  --start-time 2026-05-12T00:00:00Z \
  --end-time 2026-05-13T00:00:00Z \
  --period 3600 \
  --statistics Sum

Result: Sum = 847. Messages are reaching SNS.

Step 2 — Check delivery outcome:

aws cloudwatch get-metric-statistics \
  --namespace AWS/SNS \
  --metric-name NumberOfNotificationsFailed \
  --dimensions Name=TopicName,Value=order-events \
  --start-time 2026-05-12T00:00:00Z \
  --end-time 2026-05-13T00:00:00Z \
  --period 3600 \
  --statistics Sum

Result: Sum = 847. Every single delivery attempt failed. NumberOfNotificationsFilteredOut is zero, so filter policies are not involved.

Step 3 — Check the SQS queue policy:

aws sqs get-queue-attributes \
  --queue-url https://sqs.us-east-1.amazonaws.com/111122223333/order-processing-queue \
  --attribute-names Policy

Result: no Policy attribute. The queue has no resource policy. SNS does not have permission to write to it.

Step 4 — Add the policy:

Add the sqs:SendMessage resource policy scoped to the SNS topic ARN (as shown in the SNS to SQS section above).

Step 5 — Verify:

aws sns publish \
  --topic-arn arn:aws:sns:us-east-1:111122223333:order-events \
  --message '{"orderId":"test-001","status":"placed"}'

aws sqs receive-message \
  --queue-url https://sqs.us-east-1.amazonaws.com/111122223333/order-processing-queue

The message appears in SQS within seconds.

Why this worked. SNS was publishing successfully but had no permission to write to the SQS queue. The subscription showed as active because SNS does not validate queue permissions at subscription creation time. It only discovers the missing permission during the actual delivery attempt, and fails silently from the publisher’s perspective.

Summary

  • ”Published” and “delivered” are different states. Check NumberOfNotificationsFailed and NumberOfNotificationsFilteredOut before tracing individual subscriptions.
  • SNS to SQS: the SQS queue must have a resource policy allowing sqs:SendMessage from sns.amazonaws.com. This is the most common silent failure cause. KMS-encrypted queues also need SNS access to the KMS key.
  • SNS to Lambda: the Lambda function needs a resource-based policy allowing lambda:InvokeFunction from sns.amazonaws.com. Also check for throttling.
  • SNS to HTTP/HTTPS: confirm the subscription is past PendingConfirmation, the endpoint is publicly reachable, and it returns a 2xx response within the timeout window.
  • Filter policies skip non-matching messages silently. Check FilterPolicyScope — attribute-matching versus body-matching is a common source of missed deliveries.
  • Enable delivery status logging before production. Topic metrics tell you scale; per-delivery logs tell you cause and which subscription is involved.
  • Configure DLQs on subscriptions before going live. Messages lost before a DLQ is added cannot be recovered.

Frequently asked questions

Why does SNS say the message was published but my subscriber received nothing?

"Published" means SNS accepted the message into the topic, not that any subscriber received it. Delivery and publication are separate stages. SNS can report a successful publish while silently failing every delivery attempt due to a missing SQS queue policy, an absent Lambda permission, a filter policy mismatch, an unconfirmed HTTP subscription, or an unreachable endpoint. Check CloudWatch for NumberOfNotificationsFailed and NumberOfNotificationsFilteredOut to identify which problem is occurring.

Are SNS delivery failures retried?

Yes, but behavior varies by endpoint type. For HTTP/HTTPS endpoints, SNS retries using exponential backoff according to the subscription delivery policy. For Lambda, SNS retries throttled invocations up to 3 times with a 1-second delay between attempts. For SQS, SNS retries permission or queue errors. After all retries are exhausted, messages are permanently discarded unless a DLQ is configured on the subscription.

Do filtered-out messages count as failures?

No. Messages that do not match a subscription filter policy appear under NumberOfNotificationsFilteredOut, not NumberOfNotificationsFailed. They are silently skipped and do not trigger failure alarms, nor do they go to a DLQ. Filtered-out messages are by design, not errors.

Can I see which subscriber failed?

Not from topic-level CloudWatch metrics, which are aggregated across all subscriptions. To get per-subscription visibility, enable SNS delivery status logging to CloudWatch Logs on the topic. Each delivery attempt is logged with the subscription ARN, endpoint, and failure reason. A subscription-level DLQ also captures messages that exhausted all retries.

When should I use a DLQ on an SNS subscription?

Whenever losing a message is not acceptable. Without a DLQ, messages that exhaust all SNS retry attempts are permanently discarded with no record. Configure the DLQ before going to production, because messages that fail before the DLQ is added cannot be recovered retroactively. The DLQ must be an SQS queue in the same AWS account and region as the subscription.

Last verified: 13 May 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.