How to Fix FCM

How to Fix FCM "MismatchSenderId" in Multi-Environment Expo (EAS) Builds

Leader 3 24
calendar_today agoschedule3 min read
— Originally published at dev.to

How to Fix MismatchSenderId in Expo EAS Push Notifications Across Multiple Environments

If you are managing multiple environments (Staging, Preview, Production) in a React Native Expo app, setting up Firebase Cloud Messaging (FCM) can quickly turn into a credential nightmare.

You set up separate Firebase projects for each environment, download your config files, and configure your service accounts. Everything looks right. But when you test push notifications on your staging build, you hit a wall:

Error: MismatchSenderId

This error doesn't mean your code is broken. It means you've hit a structural limitation in how Expo EAS handles push credentials.

Here is exactly why this happens and how to architect a clean solution.


Why the Mismatch Happens

The MismatchSenderId error occurs because of a strict identity mismatch:

The device token was generated by Firebase Project A, but the notification payload was dispatched using credentials from Firebase Project B.

In a standard web or backend setup, this is easy to manage. But in the Expo ecosystem, you run into the EAS Project Limit:

Expo maps push notification service accounts per EAS Project, not per EAS Build Profile (development, preview, production).

When you run eas credentials or use the automated CLI prompts, EAS expects one default push notification Service Account (SA) key for the entire project.

If you try to reuse or attach the same service account across different Google Cloud/Firebase projects via IAM permissions, FCM will reject the cross-project token request, throwing MismatchSenderId.


If you want to rely on Expo's automated push notification infrastructure without overriding credentials constantly, the cleanest architectural fix is to separate your environments at the EAS project level.

Instead of one EAS project with multiple build profiles, initialize separate EAS projects in your ecosystem:

  • your-app-staging
  • your-app-production

Implementation Steps

In your app.json, dynamically switch the expo.projectId and expo.slug based on an environment variable during your build step:

{
  "expo": {
    "name": "Your App",
    "slug": "your-app-production",
    "extra": {
      "eas": {
        "projectId": "YOUR-PROD-PROJECT-ID"
      }
    }
  }
}

Link your staging build profile to your staging EAS project.

Run eas credentials for each project separately. This allows you to upload the staging FCM Service Account to your staging EAS project, and the production FCM Service Account to your production EAS project.


Solution 2: Bypass EAS and Route Tokens on Your Backend

If separating your EAS projects isn't an option and you need to keep everything under a single Expo App ID, you have to stop relying on Expo's unified push notification server and handle routing downstream.

Implementation Steps

Tag Tokens by Environment

When your app requests a push notification token using Expo.getExpoPushTokenAsync(), append the current build environment metadata before sending it to your database:

const token = await Expo.getExpoPushTokenAsync();

// Save to backend alongside the environment flag
await saveTokenToBackend({
  token: token.data,
  environment: process.env.EXPO_PUBLIC_APP_ENV // 'staging' or 'production'
});

Handle Routing on Your Server

On your backend infrastructure, do not use a single global Firebase initialization instance.

Initialize multiple Firebase Admin SDK instances using the respective service account JSON keys for each environment.

When triggering a notification, check the token's environment tag and dispatch it explicitly through the matching Firebase Admin instance.


Verification Checklist Before Your Next Build

Before you trigger your next EAS build, double-check that your native configuration files aren't bleeding into each other:

  • Config Plugins: Ensure your app.json or app.config.js uses a dynamic config plugin to load google-services.json (Android) and GoogleService-Info.plist (iOS) based on the target build profile. If your staging build accidentally bundles the production google-services.json, your token identities will instantly mismatch.

  • Sender IDs: Verify that the sender ID inside your bundled client-side Firebase config explicitly matches the project ID of the service account used by your notification server.


I actually built a quick web tool called Fix My Error to automate troubleshooting these kinds of React Native, Expo, and Gradle build traps. If you're stuck on a cryptic error log, feel free to drop it in there to grab the configuration fix.

🔥 Join developers growing publicly
Share your knowledge, build in public, and grow your developer presence with a global community.

More Posts

React Native Quote Audit - USA

kajolshah - Mar 2

I’m a Senior Dev and I’ve Forgotten How to Think Without a Prompt

Karol Modelskiverified - Mar 19

How I Built a React Portfolio in 7 Days That Landed ₹1.2L in Freelance Work

Dharanidharan - Feb 9

I Wrote a Script to Fix Audible's Unreadable PDF Filenames

snapsynapseverified - Apr 20

How to Fix "Module Could Not Be Found" in React Native & Expo

Asta Silva - Jun 16
chevron_left
1.8k Points27 Badges
16Posts
6Comments
5Connections
React Native developer focused on Android builds, Gradle issues, and debugging real-world errors.

I... Show more

Related Jobs

View all jobs →

Commenters (This Week)

2 comments
1 comment
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!