android fcm debugging

Your Android notifications are being dropped by a channel you never created

The notification reports delivered and the phone shows nothing. If it names a channel_id, that is almost certainly where it went — plus the thing about channel importance that will surprise you.

· 4 min read · Notibase

The symptom is always the same. FCM returns a message id. The delivery log says delivered. The phone shows nothing, and it has shown nothing for every test you have run in the last hour.

If the notification names a channel_id, that is almost certainly where it went.

What Android actually does

Since Android 8.0 (API 26), every notification belongs to a channel, and the channel has to exist on the device before the notification arrives. Your app creates it, once, by calling createNotificationChannel.

If a notification names a channel the app has not created, the system discards it. Not queues, not falls back — discards. There is no error, no callback, and nothing in logcat unless you are looking for it. FCM's job finished when it handed the message to the device, so as far as your dashboard is concerned the send worked.

This is why the bug survives so long: every layer you can see reports success, and the only layer that knows is the one that threw it away silently.

Confirming it in thirty seconds

On the device:

adb shell dumpsys notification --noredact | grep -A2 "your.package.name"

Or, more directly, list the channels your app has actually registered:

adb shell cmd notification list_channels your.package.name

If the channel your payload names is not in that list, you have found it. Send the same notification with no channel_id at all — if it appears, that is your confirmation.

The three ways it happens

A typo, or a rename. The server says orders_v2 and the app creates orders. Nothing anywhere compares the two strings, and they are in different repositories written by different people. This is the common one.

The channel is created too late. createNotificationChannel is often called when the relevant screen first opens, so a user who installs the app, never opens that screen, and receives a push has no channel. Create every channel in Application.onCreate — it is cheap, idempotent, and the only timing that is always correct.

A fresh install of an app that used to work. The channel was created by a build you no longer ship. Existing installs still have it; new ones do not. The notification works for you and fails for everybody who installed this week, which is the version of this bug that takes longest to believe.

The fix, and the thing that will surprise you

Create the channel at app start:

// Application.onCreate — every channel, every launch. Creating one that
// already exists does nothing, so there is no reason to be clever about it.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val channel = NotificationChannel(
        "orders",
        "Order updates",
        NotificationManager.IMPORTANCE_HIGH,
    )
    channel.description = "Shipping and delivery updates for your orders."
    getSystemService(NotificationManager::class.java)
        .createNotificationChannel(channel)
}

Now the surprise: once a channel exists, your app can never change its importance again. Not on upgrade, not by deleting and recreating it. The system deliberately remembers a channel's settings for the lifetime of the install, because the point of channels is that the user controls them, not you.

So if you shipped IMPORTANCE_DEFAULT and later decide these notifications should make a sound, changing the constant does nothing for anyone who already has the app. The only route is a new channel with a new id — and then the people on the old one keep the old behaviour until they clear data or reinstall. Get the importance right the first time, and split channels by what a person would plausibly want to turn off separately rather than by what is convenient for your code.

Deleting a channel does not reset this either. Delete orders and recreate it with different settings and Android restores the settings it remembered, which is a genuinely disorienting afternoon if you do not know it is happening.

While you are in there

Two adjacent things that produce the same "delivered but invisible" symptom, so they are worth ruling out in the same session:

  • A data-only FCM message. No notification block means the system draws nothing at all and expects your app to build it. That one is its own post.
  • A channel_id that is right but whose channel the user has switched off. Also silent, also reported as delivered, and the only way to know is areNotificationsEnabled() and getNotificationChannel(id).importance from inside the app.

If you would rather check the payload before you go device-hunting, we built a push payload validator that flags the channel case and a dozen others. It runs entirely in your browser — nothing is uploaded — and it needs no account.


We build Notibase, which sends push, email, SMS and in-app messages to one audience through one API on your own Firebase and APNs credentials. Our delivery error reference covers what each provider failure actually means.