GCP Pub/Sub Delivery Failures: Backlogs, Push Errors, Dead Letters
Your Pub/Sub messages are not arriving where they should. Maybe the backlog keeps growing, your push endpoint returns errors, or messages silently disappear. This page helps you figure out exactly where the pipeline is broken (publisher, subscription, subscriber, permissions, or retry configuration) and fix it.
A “message delivery failure” means a message was published to a topic but never successfully reached and was acknowledged by the subscriber. The message might be stuck in a backlog, rejected by a push endpoint, redelivered repeatedly, or routed to a dead-letter topic. Each of these patterns has a different root cause and a different fix.
If you are new to Pub/Sub, start with the Pub/Sub Overview to understand topics, subscriptions, and how delivery works. This page assumes you have a topic and at least one subscription already created.
How Pub/Sub delivery works in plain English
When Pub/Sub is healthy, the flow looks like this: your application publishes a message to a topic. Every subscription attached to that topic gets its own copy of the message. If the subscription uses pull, the subscriber fetches the message and acknowledges it. If the subscription uses push, Pub/Sub sends the message via HTTP POST to an endpoint, and a 2xx response counts as acknowledgement. Either way, once acknowledged, the message is done. For a deeper comparison of these delivery modes, see Pub/Sub Push vs Pull.
The publisher is the sender dropping a letter in the mailbox. The topic is the post office that sorts and copies the letter for each recipient. The subscription is the delivery route. The subscriber is the person who opens the letter and confirms they got it. If nobody opens the letter (no ack), the postal service keeps trying. If the address is wrong (push endpoint error), the letter bounces. If too many deliveries fail, the letter goes to the dead-letter office.
A backlog is the set of messages that have been published but not yet acknowledged. A small backlog is normal. A backlog that keeps growing means your subscriber cannot keep up, is not running, or is failing to acknowledge messages.
Pull failures happen when the subscriber is not pulling, not acknowledging, or losing the ack race against the deadline. Push failures happen when the HTTP endpoint returns an error, is unreachable, or rejects the request due to authentication. The symptoms and fixes are different for each.
A dead-letter topic is a safety net. After a message fails delivery approximately a configured number of times, Pub/Sub forwards it to the dead-letter topic instead of retrying forever. Without one, messages that can never be processed expire silently after the retention window.
Are messages not being published at all, or are they
published but not consumed? These are completely different problems
with completely different fixes. Check
topic/send_message_operation_count first to find out which side is broken.
The delivery pipeline at a glance
Every Pub/Sub message follows this path. When delivery fails, exactly one stage in this pipeline is broken:
- Publisher sends a message to a topic
- The topic fans out the message to every attached subscription
- The subscription delivers to the subscriber (pull) or push endpoint (push)
- The subscriber processes the message and sends an acknowledgement
- If acknowledgement fails repeatedly, the message goes to the dead-letter topic (if configured) or stays in the backlog until retention expires
Understanding this pipeline helps you narrow the problem. A zero publish count means step 1 is broken. A growing backlog with active publishing means steps 3–5 are broken. The Pub/Sub Messaging Model page explains the fan-out and ordering mechanics in detail.
Use this page when…
- Your subscription backlog keeps growing and never drains
- Your pull subscriber appears healthy but messages repeat endlessly
- Your push endpoint returns 403, 404, or 500 errors
- Messages are landing in your dead-letter topic
- Published messages never appear in the subscription at all
- The oldest unacked message age keeps rising
- Your subscriber processes messages but the backlog does not shrink
- A Cloud Function or Cloud Run service triggered by Pub/Sub is not receiving events
Fast triage checklist
Use this table to jump straight to the most likely cause based on what you are seeing:
| Symptom | Likely failing component | What to check first | Fix direction |
|---|---|---|---|
Zero send_message_operation_count | Publisher | Publisher logs, client errors, network, quotas | Fix the publishing application |
| Backlog growing, no pull activity | Pull subscriber | Is the subscriber running? Check process/pod status | Start or redeploy the subscriber |
| Backlog growing, subscriber running | Ack failure | Ack deadline vs processing time, ack logic in code | Increase ack deadline or fix ack logic |
| Push returns 403 | IAM / auth | Service agent roles/run.invoker, push auth config | Grant missing IAM role |
| Push returns 404 | Endpoint URL | Endpoint URL correctness, service deployment status | Fix URL or redeploy the service |
| Push returns 5xx | Endpoint application | Endpoint logs, application errors, resource limits | Fix the endpoint application |
| Messages in dead-letter topic | Subscriber processing | Dead-letter message content, subscriber error logs | Fix processing logic, then reprocess |
| Published messages never appear | Topic-subscription binding | Subscription attached to the correct topic, subscription not expired | Verify or recreate the subscription |
Check monitoring first
Before changing any configuration, check Cloud Monitoring metrics. These tell you exactly where the pipeline is broken:
# List all available Pub/Sub metrics for your project
gcloud monitoring metric-descriptors list \
--filter="metric.type:pubsub.googleapis.com" \
--format="value(type)"Key metrics and what they tell you
topic/send_message_operation_count. How many messages your publisher is sending. Zero means no messages are being published and the problem is on the publisher side, not the subscriber side.subscription/num_undelivered_messages. The current backlog size. A number that keeps growing means subscribers are falling behind or not running.subscription/oldest_unacked_message_age. The age (in seconds) of the oldest unacknowledged message. A high and rising number means the subscriber is stalled. A stable low number means delivery is healthy.subscription/push_request_count. Push delivery attempts broken down by HTTP response code. High counts at non-2xx codes mean your push endpoint is rejecting messages.subscription/pull_request_count. Pull requests from subscribers. Zero means no subscriber is pulling.subscription/dead_letter_message_count. Messages forwarded to the dead-letter topic. A growing count means your subscriber consistently fails to process certain messages.
You can set up alerting policies on these metrics so you catch delivery failures before the backlog becomes critical. For custom counters based on log patterns, see log-based metrics.
# Quick check: see the current backlog and oldest message age
gcloud pubsub subscriptions describe my-subscription \
--format="table(name,numUndeliveredMessages,messageRetentionDuration)"
# Check push delivery response codes in the last hour
gcloud monitoring time-series list \
--filter='metric.type="pubsub.googleapis.com/subscription/push_request_count"
AND resource.labels.subscription_id="my-push-subscription"' \
--interval-start-time=$(date -u -d '-1 hour' +%Y-%m-%dT%H:%M:%SZ) \
--format="table(metric.labels.response_code, points.value.int64Value)"Publisher-side delivery failures
If topic/send_message_operation_count is zero or dropping, messages are not
being published. The problem is in your publishing application, not Pub/Sub.
Messages not being published at all
Check your publisher application logs first. Common causes:
Publisher client not initialised or not connected. Verify the Pub/Sub client library is creating a publisher successfully and that the topic name is correct. A typo in the topic name causes a NOT_FOUND error on every publish.
Authentication failure. The service account running the publisher needs
roles/pubsub.publisheron the topic. Missing credentials or wrong service account produce PERMISSION_DENIED errors. See troubleshooting authentication errors for credential diagnostics.Pub/Sub API not enabled. The Pub/Sub API must be enabled in the project. A PERMISSION_DENIED or SERVICE_DISABLED error on publish calls means the API is off.
# Check if the Pub/Sub API is enabled
gcloud services list --enabled --filter="name:pubsub.googleapis.com"
# Verify the topic exists
gcloud pubsub topics describe my-topic
# Check IAM policy on the topic
gcloud pubsub topics get-iam-policy my-topicRun gcloud pubsub topics publish my-topic —message=“hello” from your
terminal. If it succeeds, Pub/Sub and the topic are fine. The problem is in your
publisher code. If it fails, the error message tells you exactly what is wrong
(wrong topic name, missing API, missing permissions).
Publisher timeouts and throughput issues
DEADLINE_EXCEEDED errors. The publish call timed out before Pub/Sub confirmed receipt. This can happen under network pressure, high message volume, or when the publisher machine is CPU/memory constrained. Increase the publish timeout in your client configuration or reduce batch size.
Quota limits. Pub/Sub has per-project quotas on publish throughput. If you hit them, publish calls return RESOURCE_EXHAUSTED. Check your quota usage in the Cloud Console under IAM & Admin > Quotas.
Large messages. Pub/Sub has a 10 MB maximum message size. Messages exceeding this limit are rejected. If your payloads are large, store the data in Cloud Storage and publish a reference instead.
How to confirm publish is working
# Publish a test message and confirm it succeeds
gcloud pubsub topics publish my-topic \
--message="test message $(date -u +%Y-%m-%dT%H:%M:%SZ)"
# If this succeeds, your topic is fine and the problem is in your publisher code
# If this fails, read the error message — it tells you what is wrongPull subscription failures
Pull subscriptions require the subscriber to actively fetch messages. If nothing is pulling, messages accumulate in the backlog until the retention window expires (default 7 days).
No active subscriber
The most basic pull failure: no process is pulling from the subscription. Check whether your subscriber application, container, or Cloud Function is actually running. A crashed pod, a stopped VM, or an undeployed function means zero pull activity and a growing backlog.
# Manually pull messages to confirm the subscription works
gcloud pubsub subscriptions pull my-subscription \
--limit=5 \
--auto-ack
# If messages come back, the subscription is fine — your subscriber is not pulling
# Pull without acknowledging (messages redeliver after ack deadline)
gcloud pubsub subscriptions pull my-subscription \
--limit=5Subscriber not acknowledging messages
Your subscriber pulls messages and processes them, but never sends an acknowledgement. Pub/Sub redelivers unacknowledged messages after the ack deadline expires. This creates a loop: the same messages arrive again and again, the backlog never drains, and you see duplicate processing in your logs.
Fix: ensure every code path that successfully processes a message calls ack().
Check error handling paths too. A caught exception that skips the ack causes silent
redelivery.
Ack deadline too short
The default ack deadline is only 10 seconds. If your subscriber does anything slower than that (a database write, an HTTP call, image processing), Pub/Sub assumes the message was lost and sends it again. You end up processing the same message multiple times while the backlog never shrinks. This is the most confusing failure because everything looks like it is working.
If your processing involves database writes, HTTP calls to slow APIs, or heavy computation, the deadline expires before processing finishes. Pub/Sub assumes the message was not processed and redelivers it.
# Check the current ack deadline
gcloud pubsub subscriptions describe my-subscription \
--format="value(ackDeadlineSeconds)"
# Increase the ack deadline to 60 seconds
gcloud pubsub subscriptions update my-subscription \
--ack-deadline=60For variable processing times, use modifyAckDeadline in your client code
to extend the deadline dynamically while processing is still in progress.
Slow processing causing backlog growth
If messages arrive faster than your subscriber can process them, the backlog grows even though everything is technically working. Solutions: increase the number of subscriber instances, increase concurrency within each subscriber, or optimise processing time.
Missing IAM permissions
The service account running your subscriber needs roles/pubsub.subscriber
on the subscription. Without it, every pull request fails with
PERMISSION_DENIED.
# Check who has subscriber access
gcloud pubsub subscriptions get-iam-policy my-subscription
# Grant subscriber role to your service account
gcloud pubsub subscriptions add-iam-policy-binding my-subscription \
--member="serviceAccount:my-sa@my-project.iam.gserviceaccount.com" \
--role="roles/pubsub.subscriber"Push subscription failures
Push subscriptions deliver messages via HTTP POST to an endpoint URL. Pub/Sub retries
with exponential backoff on any non-success response. If the endpoint consistently
returns errors, the backlog grows and
push_request_count shows high error rates.
Understanding push response codes
Pub/Sub treats responses 200, 201, 202, 204, and 102 as successful delivery. Everything else is a failure that triggers a retry:
403 Forbidden: almost always an IAM issue. The Pub/Sub service agent does not have permission to invoke the endpoint. This is the most common push failure for private Cloud Run and Cloud Functions endpoints.
404 Not Found: the endpoint URL is wrong, the service is not deployed, or the route does not exist. Verify the URL and confirm the service is running.
401 Unauthorized: push authentication is configured but the endpoint is rejecting the JWT token. Check that the audience in the push config matches what your endpoint expects.
5xx Server Error: your endpoint application is crashing. Check the endpoint logs (not Pub/Sub logs) to find the application error. Use Logs Explorer filtered to your Cloud Run or Cloud Functions service.
Timeout / unreachable: the endpoint did not respond within the push timeout, or Pub/Sub cannot reach it. Check firewall rules, VPC configuration, and whether the endpoint is publicly accessible (or correctly configured for internal access).
Pub/Sub does not log individual push delivery failures in Cloud Logging by default.
If your push endpoint is returning errors, you will only see them in the
push_request_count metric or in your endpoint’s own logs. Do not assume
“no errors in Pub/Sub logs” means delivery is healthy.
# Check the push endpoint URL and auth configuration
gcloud pubsub subscriptions describe my-push-subscription \
--format="yaml(pushConfig)"
# Update the push endpoint URL
gcloud pubsub subscriptions modify-push-config my-push-subscription \
--push-endpoint=https://my-service-abc123-uc.a.run.app/pubsubPush authentication and JWT issues
When push authentication is enabled, Pub/Sub includes a signed JWT in the Authorization header. Your endpoint must validate this token. Common problems:
- The
audiencein the push config does not match what the endpoint checks - The service account specified in the push config does not exist or is disabled
- The endpoint validates the token issuer but uses the wrong expected value
Private Cloud Run and Cloud Functions endpoints
This is the single most common push delivery failure. If your Cloud Run service or Cloud
Function requires authentication (the default), the Pub/Sub service agent must have
roles/run.invoker (for Cloud Run) or roles/cloudfunctions.invoker
(for Cloud Functions) granted on the service. Without it, every push returns 403. For more
on how Cloud Run authentication works, see the
Cloud Run Security Model guide.
# Find your project number (needed for the service agent email)
gcloud projects describe PROJECT_ID --format="value(projectNumber)"
# Grant Pub/Sub permission to invoke a private Cloud Run service
gcloud run services add-iam-policy-binding my-cloud-run-service \
--region=us-central1 \
--member="serviceAccount:service-PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com" \
--role="roles/run.invoker"
# Grant Pub/Sub permission to invoke a Cloud Function (gen2)
gcloud functions add-invoker-policy-binding my-function \
--region=us-central1 \
--member="serviceAccount:service-PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com"The Pub/Sub service agent email follows the pattern
service-PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com.
Use the numeric project number, not the project ID. These are different values.
Firewall and endpoint reachability
Push delivery comes from Google-owned IP ranges. If your endpoint is behind a firewall or in a VPC with restrictive ingress rules, Pub/Sub cannot reach it. For Cloud Run and Cloud Functions with default settings, this is not an issue. For custom endpoints behind a load balancer or on a VM, ensure the firewall allows HTTPS traffic from Google’s IP ranges.
Reading push failure patterns from logs
Pub/Sub itself does not log individual push attempts in Cloud Logging by default. To diagnose push failures:
- Check
push_request_countmetric grouped byresponse_codeto see the pattern - Check the endpoint service logs (Cloud Run, Cloud Functions, or your own server) for the corresponding errors
- If your endpoint is a Cloud Function triggered by Pub/Sub, see debugging Cloud Functions failures for log query guidance
- Enable audit logging for Pub/Sub if you need to trace individual delivery attempts
Dead-letter topics and retry behaviour
What dead-letter topics do
A dead-letter topic is a separate topic that receives messages your subscription could not deliver after repeated attempts. Instead of retrying forever until the retention window expires, Pub/Sub forwards the message to the dead-letter topic so you can inspect it, fix the problem, and reprocess.
Maximum delivery attempts are approximate
When you set —max-delivery-attempts=10, Pub/Sub forwards the message after
approximately 10 failed deliveries. The actual count may be slightly higher or
lower due to the distributed nature of the system. Do not design logic that depends on an
exact attempt count.
IAM requirements for dead-lettering
If the Pub/Sub service agent does not have the correct permissions, dead-lettering quietly does nothing. Messages stay in the backlog as if no dead-letter topic exists. There is no error message. You only discover it when you notice the dead-letter subscription has zero messages while the source backlog keeps growing.
The Pub/Sub service agent needs two permissions:
roles/pubsub.publisheron the dead-letter topic (to publish forwarded messages)roles/pubsub.subscriberon the source subscription (to acknowledge forwarded messages)
# Create a dead-letter topic and a monitoring subscription
gcloud pubsub topics create my-subscription-dead-letter
gcloud pubsub subscriptions create my-dead-letter-monitor \
--topic=my-subscription-dead-letter
# Configure dead-letter policy on the source subscription
gcloud pubsub subscriptions update my-subscription \
--dead-letter-topic=my-subscription-dead-letter \
--max-delivery-attempts=10
# Grant the service agent permission to publish to the dead-letter topic
gcloud pubsub topics add-iam-policy-binding my-subscription-dead-letter \
--member="serviceAccount:service-PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com" \
--role="roles/pubsub.publisher"
# Grant the service agent permission to ack on the source subscription
gcloud pubsub subscriptions add-iam-policy-binding my-subscription \
--member="serviceAccount:service-PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com" \
--role="roles/pubsub.subscriber"Retry policy vs push backoff
Pub/Sub has two separate retry mechanisms that are easy to confuse:
Retry policy (configured on the subscription): controls the minimum and maximum delay between redelivery attempts. Applies to both pull and push subscriptions. Default is immediate redelivery with no delay.
Push backoff: an automatic exponential backoff Pub/Sub applies to push endpoints that return errors. The backoff increases with consecutive failures and can reach minutes between attempts. This happens on top of any configured retry policy.
For pull subscriptions, the retry policy adds delay between redeliveries. For push subscriptions, the exponential backoff from consecutive failures is the dominant delay. You can configure the retry policy to add a minimum backoff for pull redeliveries:
# Set a retry policy with minimum 10s and maximum 600s backoff
gcloud pubsub subscriptions update my-subscription \
--min-retry-delay=10s \
--max-retry-delay=600sWhen to use a dead-letter topic
Configure a dead-letter topic when:
- Message loss is unacceptable and you need to capture every failed message for investigation
- Some messages are “poison pills” that will never process successfully and would block other messages
- You want to separate healthy delivery from failed delivery for monitoring purposes
Inspecting dead-lettered messages
# Pull messages from the dead-letter monitoring subscription
gcloud pubsub subscriptions pull my-dead-letter-monitor \
--limit=10 \
--format="table(message.data.decode(base64), message.attributes)"
# Each dead-lettered message includes these attributes:
# - CloudPubSubDeadLetterSourceSubscription: which subscription forwarded it
# - CloudPubSubDeadLetterSourceDeliveryCount: approximate delivery attemptsRead the message body and the source subscription attribute. This tells you which subscription failed and what the message contained. Fix the subscriber, then decide whether to replay the dead-lettered messages or reprocess them manually.
Recover after the fix
After you fix the root cause, verify that delivery is actually recovering:
Confirm the backlog is draining
# Watch the backlog size decrease over time
gcloud pubsub subscriptions describe my-subscription \
--format="value(name, numUndeliveredMessages)"
# Check oldest unacked message age — it should be droppingThe num_undelivered_messages metric should trend down and
oldest_unacked_message_age should stabilise or drop. If neither changes,
the fix did not work or there is a second problem.
Validate push delivery recovery
After fixing a push endpoint, check push_request_count grouped by
response code. You should see 2xx responses increasing and error responses dropping.
Push backoff may cause a delay before Pub/Sub ramps delivery back up after a
prolonged failure period.
Verify subscriber acknowledgements
Check subscription/ack_message_count in Cloud Monitoring. A healthy
subscriber shows a steady ack rate that matches or exceeds the publish rate.
Decide whether to replay messages
If messages were lost during the outage or if you need to reprocess messages from a specific point in time, Pub/Sub supports seek operations. You can seek to a timestamp to replay all messages published after that time, or seek to a snapshot to replay from a saved state. Use seek carefully because it redelivers messages that were already successfully processed. Your subscriber must handle duplicates safely.
# Seek to a timestamp to replay messages from that point forward
gcloud pubsub subscriptions seek my-subscription \
--time="2026-03-27T10:00:00Z"
# Create a snapshot for future replay points
gcloud pubsub snapshots create my-snapshot \
--subscription=my-subscriptionPush vs pull failure patterns
Push is like a doorbell: Pub/Sub walks up to your endpoint and rings. If nobody answers (non-2xx), Pub/Sub walks away and comes back later, waiting longer each time. Pull is like a mailbox: messages sit there until your subscriber checks. If nobody checks, the mailbox overflows. The failure modes are different because the delivery model is different.
| Pull subscription | Push subscription | |
|---|---|---|
| How failure appears | Backlog grows, pull_request_count at zero or low | Backlog grows, push_request_count shows non-2xx codes |
| Where errors show up | Subscriber application logs, Cloud Monitoring pull metrics | Push response code metrics, endpoint service logs |
| Common root causes | Subscriber not running, not acking, ack deadline too short, missing roles/pubsub.subscriber | Endpoint returning errors, missing roles/run.invoker, wrong URL, auth misconfiguration |
| Retry behaviour | Messages redeliver after ack deadline expires; retry policy adds configurable delay | Automatic exponential backoff on consecutive errors; can slow to minutes between attempts |
| Best first diagnostic action | Manually gcloud pubsub subscriptions pull to verify messages exist | Check push_request_count by response code to identify the HTTP error pattern |
For a full comparison of when to use each delivery type, see Pub/Sub Push vs Pull.
Checking subscription configuration
Many delivery failures trace back to misconfigured subscriptions. Check these fields:
# Describe a subscription — inspect all key fields
gcloud pubsub subscriptions describe my-subscription
# Key fields to check:
# - topic: the topic this subscription receives from
# - pushConfig.pushEndpoint: URL for push subscriptions (empty for pull)
# - ackDeadlineSeconds: how long before unacked messages are redelivered
# - messageRetentionDuration: how long undelivered messages are kept
# - deadLetterPolicy: dead-letter topic and max delivery attempts
# - retryPolicy: min and max backoff for redelivery
# List all subscriptions attached to a topic
gcloud pubsub topics list-subscriptions my-topicCommon mistakes
Not acknowledging messages after processing. This is the most common cause of a growing backlog. Unacknowledged messages are redelivered after the ack deadline, creating a loop of duplicate processing. Ensure every successful processing path calls
ack(), including inside error-handling branches that swallow exceptions.Not configuring a dead-letter topic. Without one, messages that repeatedly fail processing are silently lost after the retention window expires. For any pipeline where message loss matters, configure a dead-letter topic and monitor it.
Forgetting to grant the Pub/Sub service agent
roles/run.invokerfor private push endpoints. Every push delivery to a private Cloud Run or Cloud Functions service fails with 403 unless the service agent has the invoker role. This is the single most common push delivery failure.Setting the ack deadline too short for the actual processing time. If your processing takes 30 seconds but the ack deadline is 10 seconds, Pub/Sub redelivers the message twice before processing finishes. Increase the deadline or use
modifyAckDeadlineto extend it dynamically.Assuming the dead-letter attempt count is exact. The
—max-delivery-attemptsvalue is approximate. Do not build logic that expects exactly N attempts before dead-lettering. Design your subscriber to be idempotent so that extra delivery attempts do not cause problems.Forgetting IAM grants for dead-letter forwarding. The Pub/Sub service agent needs
roles/pubsub.publisheron the dead-letter topic androles/pubsub.subscriberon the source subscription. Without both, dead-lettering silently fails and messages stay in the backlog forever.Blaming the subscriber when the publisher is broken. Always check
topic/send_message_operation_countfirst. If no messages are being published, fixing the subscriber does nothing. Separate publisher-side from subscriber-side failures before debugging.
How to confirm it is fixed
After applying your fix, verify these indicators over the next 15–30 minutes:
num_undelivered_messagesis trending down (backlog draining)oldest_unacked_message_agehas stabilised or is droppingpush_request_countshows 2xx responses (for push subscriptions)dead_letter_message_counthas stopped growingack_message_countshows steady acknowledgements matching the publish rate- Subscriber application logs show successful processing without repeated errors
If the backlog is not draining after 15 minutes, there may be a second issue or the fix did not fully resolve the problem. Re-check the triage table and metrics.
Summary
- Check
send_message_operation_countfirst to separate publisher failures from subscriber failures - A growing
num_undelivered_messageswith active publishing means the subscriber side is broken - Pull subscribers must fetch and acknowledge messages or the backlog grows indefinitely
- Push endpoints must return 2xx; anything else triggers retries with exponential backoff
- Private Cloud Run push endpoints need the Pub/Sub service agent to have
roles/run.invoker - Dead-letter topics require IAM grants for both publishing and subscribing to work correctly
- Maximum delivery attempts are approximate, not exact
- Increase the ack deadline for processing that takes longer than 10 seconds
- Use seek to replay messages after fixing an outage, but be aware it redelivers already-processed messages
Frequently asked questions
How do I tell whether Pub/Sub delivery failures are on the publisher side or subscriber side?
Check the Cloud Monitoring metric topic/send_message_operation_count. If it shows zero, no messages are being published and the problem is your publisher. If messages are being published normally, check subscription/num_undelivered_messages. A growing backlog means your subscriber is not consuming or acknowledging messages. These two metrics separate publisher-side from subscriber-side failures within seconds.
What happens to Pub/Sub messages that fail delivery repeatedly?
Without a dead-letter topic, messages stay in the subscription backlog until the retention window expires (default 7 days, configurable up to 31 days), then they are permanently lost. If you configure a dead-letter topic with a max delivery attempts limit, messages that exceed approximately that many delivery attempts are forwarded to the dead-letter topic instead of expiring silently. The delivery attempt count is approximate, not exact.
Why does my push subscription keep getting 403 errors from Cloud Run?
The Pub/Sub service agent needs roles/run.invoker on your Cloud Run service. The service agent email is service-PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com (use the numeric project number, not the project ID). This is the most common cause of persistent 403 errors on push delivery to private Cloud Run services. Grant the role and push delivery resumes within seconds.
How do I stop Pub/Sub from redelivering messages my subscriber already processed?
The most common cause of redelivery is that your subscriber processes messages but does not acknowledge them, or the ack deadline expires before processing finishes. Ensure every successfully processed message gets an explicit ack. If processing takes longer than the default 10-second ack deadline, increase it with --ack-deadline on the subscription or extend it dynamically with modifyAckDeadline in your client code.
How do I inspect messages that landed in my dead-letter topic?
Create a subscription on the dead-letter topic, then pull messages from it. Each message retains its original data and attributes, plus Pub/Sub adds a CloudPubSubDeadLetterSourceSubscription attribute identifying which subscription forwarded it. Read the message body and attributes to understand the failure pattern, then fix the root cause in your subscriber before replaying or reprocessing.