Help Center Push error catalogue

Push error catalogue

Each entry starts from a symptom you can actually observe. These systems fail in each other’s disguise, so work from what you can see rather than from where you suspect the bug lives.

FCM send errors

ResponseUsual causeFix
404 UNREGISTERED / NotRegisteredThe backend is sending the installation id where message.token wants the registration token — or the stored token is stale.Send fcmToken at registration and upsert it on every re-registration. Delete the installation when FCM answers UNREGISTERED.
400 INVALID_ARGUMENTThe same underlying mistake as above. Both codes are reported for it.Judge on accepted-versus-rejected, not on the exact code.
403The service account belongs to a different Firebase project than the app.Match project_id across google-services.json, GoogleService-Info.plist and the service account.
PERMISSION_DENIED: Firebase Cloud Messaging API has not been used in project …FCM API (V1) is not enabled.Enable it in Firebase → Project settings → Cloud Messaging.

Nothing is registered at all

No request ever reaches the service, and no error either. The registration ran and threw somewhere that swallowed it. Look for a shared try around the installation id and the token: a token failure that nulls the id makes callers skip registration entirely. Take them independently.

FCM registration token: Object is not a function. RNFirebase v26 removed the callable messaging() namespace, so module.default ?? module yields the module object. Use the modular API.

Requests are sent and answered, but the service has no record. Check the host. restapi.smsbat.com is the push service; a neighbouring host may accept and discard the request, so the app sees success and the data goes nowhere.

Registered under an id that collides with someone else’s. Namespace externalUserId — operator-497, not 497. Operator and client ids share the space.

The push arrives but nothing appears

Nothing on screen while the app is open. Messages are data-only by design, so the system draws nothing. The foreground handler must present the notification itself from data.

Nothing while the app is backgrounded or closed. Same cause, different handler. The background handler must draw it too, and must be registered at module scope — a handler attached from a screen does not exist when the headless task starts.

Appears, but silent or without sound on Android. The channel was not created before the notification was presented, or POST_NOTIFICATIONS was never granted on Android 13+.

The push appears but no callback reaches the backend

This is the expensive one: the cascade assumes the push failed and bills for an SMS the user already read.

No callback at all, on either platform. Three services compete for MESSAGING_EVENT on Android, and on iOS both libraries want UNUserNotificationCenter.delegate. If the app listens only through expo-notifications while RNFirebase’s service wins, no listener fires. Listen on both sides and deduplicate by guid.

Callbacks arrive twice for the same message. The same message reached the app through both paths, or a locally re-presented notification came back through the expo-notifications listener. Deduplicate by data.guid.

delivered arrives only when the app is open. On Android a message carrying a notification block is drawn by the system and never reaches JS until it is tapped. Check whether a notification block crept back into the payload.

iOS specifically

Appears on Android, silent on iOS. Check the APNs auth key in Firebase, in both slots. Development-only is the usual miss, and TestFlight runs in production.

FCM token never appears, APNs token row is empty. registerDeviceForRemoteMessages() returns before the APNs token arrives. Poll getAPNSToken() before asking for the FCM token.

Everything is empty on a simulator. Expected. Apple issues no push token to a simulator. Test on a device.

Notification permission granted, still nothing. Confirm UIBackgroundModes: ["remote-notification"] is present, then check the APNs key.

Misleading results

Firebase console’s test message arrives, the API call does not. Expected, and misleading: the console resolves an installation id to a token before sending; the v1 API does not. Only the API result counts. A successful console test proves the device, permissions, APNs key and project are fine — it says nothing about what the backend sends.

The cheapest check

A FID is about 22 characters with no colon. A registration token is 140+ with a colon around position 23. Logging the token length next to every send failure makes this visible forever after.

Questions worth asking before debugging

  1. Which identifier does the backend actually send? Not which one it intends to.
  2. Is it the current one? A device reinstalled since registration has a different FID and token.
  3. Was the device sideloaded? A store build cannot update over a differently signed APK.
  4. Which build is on the device? The settings screen version, not the one in the console.
  5. Does the artifact hold the Firebase project you think it does?