GCP Pub/Sub Messages Not Delivering to Subscribers
Messages published to Pub/Sub topics aren't reaching subscribers. This usually happens after a subscription is created or when a service account lacks the right permissions.
You set up a Pub/Sub topic, published a few test messages, and nothing shows up in your subscriber. Maybe you used the console or the gcloud CLI. The subscriber is a Cloud Function, a GKE pod, or a simple Python script. The topic shows messages published (you see them in the metrics), but the subscription count stays at zero. I've seen this exact thing happen when someone creates a push subscription but forgets to configure the endpoint, or when a pull subscriber doesn't have a valid service account key.
Root Cause
The culprit here is almost always one of three things:
- Wrong IAM permissions – The subscriber's identity (service account or user) needs the
roles/pubsub.subscriberrole on the subscription. Without it, the subscriber can't pull messages or receive push deliveries. - Misconfigured push endpoint – For push subscriptions, the endpoint URL must be HTTPS and publicly accessible (or reachable via VPC-SC). If the endpoint returns a non-200 status, the message stays on the subscription.
- Pull subscriber not running – Pull subscriptions are passive. If no client actively pulls, messages just sit there. The subscriber must be running and calling the
pullmethod.
There are other gotchas like message ordering or exactly-once delivery settings, but those are rare. Start with the three above.
The Fix – Step by Step
Step 1: Check the subscription exists and is active
Run this command in Cloud Shell:
gcloud pubsub subscriptions list --format="table(name, topic, ackDeadlineSeconds, pushConfig.endpoint)"
Look for your subscription. If it's missing, create it with gcloud pubsub subscriptions create. If the topic name is wrong (typo happens), you'll see no messages.
Step 2: Verify the subscriber's IAM permissions
Find the identity your subscriber uses. For Cloud Functions it's the runtime service account. For GKE it's the node pool's service account. Run this:
gcloud pubsub subscriptions get-iam-policy YOUR_SUBSCRIPTION_NAME
If you see no roles/pubsub.subscriber binding, add it:
gcloud pubsub subscriptions add-iam-policy-binding YOUR_SUBSCRIPTION_NAME \
--member="serviceAccount:SUBSCRIBER_SA@PROJECT.iam.gserviceaccount.com" \
--role="roles/pubsub.subscriber"
Don't skip this. I've fixed dozens of issues with just this one step.
Step 3: Check the push endpoint (for push subscriptions only)
If it's a push subscription, the endpoint must respond quickly (< 10 seconds) and return a 200, 201, 204, or 102 status. Use curl to test it:
curl -X POST https://your-endpoint.com/path -H "Content-Type: application/json" -d '{"message":{"data":"dGVzdA=="}}' -w "\nHTTP Status: %{http_code}\n"
If you get a 4xx or 5xx, fix the endpoint. Also check if the endpoint is behind an HTTP(S) load balancer – make sure the backend service is healthy.
Step 4: For pull subscriptions – test with a simple subscriber
If you're using a custom pull subscriber, test it with the CLI first:
gcloud pubsub subscriptions pull YOUR_SUBSCRIPTION_NAME --auto-ack --limit=1
If this gets messages but your code doesn't, the bug is in your code. Most common mistake: the subscriber process crashes before acknowledging messages. Add error handling and retry logic.
Step 5: Look at the dead letter queue (if configured)
When a push endpoint fails too many times, messages go to a dead letter topic. Check if your subscription has a dead letter policy:
gcloud pubsub subscriptions describe YOUR_SUBSCRIPTION_NAME --format="value(deadLetterPolicy)"
If it's set, check the dead letter topic's subscription for your messages. You might need to replay them.
What to Check If It Still Fails
If you've done all the above and messages still aren't delivering, here's my checklist:
- Retry policy – Check the subscription's
ackDeadlineSeconds. Default is 10 seconds. If your subscriber takes longer than that, increase it (up to 600 seconds). Also checkretryPolicy– the minimum backoff is 10 seconds by default. For push, set it lower if you want faster retries. - Message ordering – If you enabled ordering keys, the subscription must also be configured for ordering. If the publisher and subscriber don't agree on the order key, messages might be stuck.
- VPC Service Controls – If you're using VPC-SC, the subscriber must be in the same perimeter, or you need an ingress rule for the Pub/Sub API.
- Quotas and limits – Pub/Sub has a limit of 10,000 outstanding messages per subscription (default). If you're publishing faster than you consume, the backlog grows. But this doesn't cause delivery failure – just delay.
- Logs – always check the logs – Go to the GCP console → Logging → Logs Explorer. Filter by resource type
pubsub_subscriptionand your subscription name. Look for errors likeDEADLINE_EXCEEDEDorPERMISSION_DENIED. This is your best debug tool.
One more thing – if you're using a push subscription and the endpoint is a Cloud Function, make sure you're using the right HTTP trigger. I've seen people use a background function (which expects raw Pub/Sub messages) with a push endpoint. That won't work. Use an HTTP trigger function that parses the Pub/Sub envelope.
That's it. Nine times out of ten, it's a permission or endpoint issue. Fix those first and you'll be back online.
Was this solution helpful?