How to fix messaging/invalid-registration-token in Firebase

FirebaseINTERMEDIATEHIGHUpdated Dec 22, 2025ยท 409 views

This error occurs when Firebase Cloud Messaging rejects a registration token because it is invalid, expired, unregistered, or no longer recognized by FCM. The fix involves validating tokens, removing stale tokens, refreshing tokens on the client side, and implementing proper token lifecycle management.

Quick fix

Fixes messaging/invalid-registration-token

// Node.js Admin SDK
const admin = require('firebase-admin');

// Check your initialized app
console.log('Firebase app:', admin.app().name);
console.log('Project ID:', admin.apps[0].options.projectId);

// Verify credentials are for the same project
const serviceAccountJson = require('./path/to/service-account-key.json');
console.log('Service account project:', serviceAccountJson.project_id);

// They must match!
if (admin.apps[0].options.projectId !== serviceAccountJson.project_id) {
  throw new Error('Firebase project mismatch!');
}
  1. Verify the Firebase project configuration
  2. Check token age and implement staleness detection
  3. Ensure client-side token refresh on app updates
  4. Handle invalid token errors and clean up database
firebase โ€” error
// Node.js Admin SDK
const admin = require('firebase-admin');
// Check your initialized app
console.log('Firebase app:', admin.app().name);
console.log('Project ID:', admin.apps[0].options.projectId);
// Verify credentials are for the same project
const serviceAccountJson = require('./path/to/service-account-key.json');
console.log('Service account project:', serviceAccountJson.project_id);
// They must match!
if (admin.apps[0].options.projectId !== serviceAccountJson.project_id) {
throw new Error('Firebase project mismatch!');
}
messaging/invalid-registration-token

What this error means

The "messaging/invalid-registration-token" error indicates that the registration token provided to Firebase Cloud Messaging (FCM) is not recognized as a valid, active FCM token. FCM registration tokens are unique identifiers that allow your backend server to send push notifications to specific devices. This error is different from "token format incorrect" - the token string itself may be properly formatted, but FCM considers it invalid because: - The token has expired (FCM marks tokens as invalid after 270 days of inactivity on Android) - The app that generated the token was uninstalled - The app was updated but not configured to receive messages - The APNS token on iOS was reported as invalid by the APNS Feedback Service - The device deleted its Instance ID - The user cleared the app data - The token was never properly registered with FCM in the first place When this error occurs, FCM returns HTTP status 400 with error code "INVALID_ARGUMENT", indicating the token should no longer be used to send messages.

Typical symptoms

  • Push notifications fail to send with INVALID_ARGUMENT status
  • Error message: "The registration token is not a valid FCM registration token"
  • Error code: messaging/invalid-registration-token
  • Failures are consistent and persistent for specific devices
  • Recently working tokens suddenly start failing
  • Tokens work intermittently then stop working entirely
  • Error occurs immediately without retry or timeout delays

Common causes

  1. Token has expired from 270+ days of inactivity (especially on Android)
  2. User uninstalled and reinstalled the app without updating your server's token store
  3. Device cleared app data or uninstalled the app but your database still contains the old token
  4. App was updated to a new version that is not configured to receive messages
  5. Client-side token generation failed silently but error wasn't caught or logged
  6. APNS token on iOS was reported as invalid by the Apple Push Notification service
  7. Device deleted its Instance ID (rare, but can happen during OS updates)
  8. Token was stored or transmitted incorrectly and corrupted
  9. Token is from a different Firebase project than the one you're sending to
  10. Token was generated in development but being used against production Firebase project

How to fix "messaging/invalid-registration-token"

1Verify the Firebase project configuration

Ensure you're sending notifications using the correct Firebase project and credentials that match where the client tokens were generated.

javascript
// Node.js Admin SDK
const admin = require('firebase-admin');

// Check your initialized app
console.log('Firebase app:', admin.app().name);
console.log('Project ID:', admin.apps[0].options.projectId);

// Verify credentials are for the same project
const serviceAccountJson = require('./path/to/service-account-key.json');
console.log('Service account project:', serviceAccountJson.project_id);

// They must match!
if (admin.apps[0].options.projectId !== serviceAccountJson.project_id) {
  throw new Error('Firebase project mismatch!');
}

Common mistake: Using development tokens against a production Firebase project, or vice versa. Always use the same project for both client generation and server sending.

2Check token age and implement staleness detection

Firebase recommends removing tokens that haven't been refreshed in 2 months. Tokens older than 270 days become invalid on Android.

Store the token timestamp with each device token:

javascript
// Schema example (Prisma)
model UserDevice {
  id                    String   @id @default(cuid())
  userId                String
  fcmToken              String   @unique
  fcmTokenReceivedAt    DateTime // Track when token was last updated
  fcmTokenInvalidatedAt DateTime? // Track when it failed
}

// Create migration
CREATE TABLE UserDevice (
  id VARCHAR(255) PRIMARY KEY,
  userId VARCHAR(255) NOT NULL,
  fcmToken VARCHAR(255) NOT NULL UNIQUE,
  fcmTokenReceivedAt TIMESTAMP NOT NULL,
  fcmTokenInvalidatedAt TIMESTAMP
);

Implement automatic cleanup:

javascript
// Remove stale tokens (older than 2 months) daily
async function cleanupStaleTokens() {
  const twoMonthsAgo = new Date();
  twoMonthsAgo.setDate(twoMonthsAgo.getDate() - 60);

  const staleTokens = await db.userDevice.findMany({
    where: {
      fcmTokenReceivedAt: {
        lt: twoMonthsAgo
      }
    }
  });

  console.log(`Found ${staleTokens.length} stale tokens`);

  // Remove them
  await db.userDevice.deleteMany({
    where: {
      id: {
        in: staleTokens.map(t => t.id)
      }
    }
  });
}

// Schedule to run daily (using node-cron or similar)
cron.schedule('0 2 * * *', cleanupStaleTokens);
3Ensure client-side token refresh on app updates

When your app is updated, ensure the client regenerates and resends the FCM token to your server. Implement token refresh listeners.

Web (JavaScript):

javascript
import { getMessaging, onMessage, getToken } from 'firebase/messaging';

async function setupMessaging() {
  try {
    const messaging = getMessaging();

    // Get initial token
    const token = await getToken(messaging, {
      vapidKey: 'YOUR_VAPID_KEY'
    });

    if (token) {
      await sendTokenToServer(token);
      console.log('FCM Token initialized:', token);
    }

    // Listen for token changes
    // This fires when the token is refreshed (app updates, user reinstalls, etc.)
    onMessage(messaging, (payload) => {
      console.log('Message received:', payload);
    });

  } catch (error) {
    console.error('Error setting up messaging:', error);
  }
}

async function sendTokenToServer(token) {
  await fetch('/api/devices/register-fcm', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ fcmToken: token })
  });
}

Android (Kotlin):

kotlin
// Firebase automatically refreshes tokens
// Handle new tokens by listening to the refresh event
class MyFirebaseMessagingService : FirebaseMessagingService() {
  override fun onNewToken(token: String) {
    Log.d(TAG, "New token: $token")

    // Send to your server immediately
    sendTokenToServer(token)
  }

  private fun sendTokenToServer(token: String) {
    val request = Request.Builder()
      .url("https://yourapi.com/api/devices/register-fcm")
      .post(RequestBody.create("application/json".toMediaType(),
        """{"fcmToken":"$token"}"""))
      .build()

    val client = OkHttpClient()
    client.newCall(request).execute()
  }
}

iOS (Swift):

swift
import Firebase
import UserNotifications

class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate {
  func application(_ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    FirebaseApp.configure()

    // Listen for token changes
    Messaging.messaging().delegate = self

    // Request user permission
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { _, _ in }
    DispatchQueue.main.async {
      UIApplication.shared.registerForRemoteNotifications()
    }

    return true
  }

  func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
    guard let token = fcmToken else { return }

    print("FCM token: \(token)")

    // Send to your server
    sendTokenToServer(token)
  }

  private func sendTokenToServer(_ token: String) {
    let url = URL(string: "https://yourapi.com/api/devices/register-fcm")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")

    let body = ["fcmToken": token]
    request.httpBody = try? JSONSerialization.data(withJSONObject: body)

    URLSession.shared.dataTask(with: request).resume()
  }
}
4Handle invalid token errors and clean up database

When you encounter this error, immediately remove or mark the token as invalid to prevent repeated failures.

javascript
// Node.js Admin SDK with proper error handling
async function sendNotification(userId, message) {
  const device = await db.userDevice.findFirst({
    where: { userId, fcmTokenInvalidatedAt: null }
  });

  if (!device || !device.fcmToken) {
    throw new Error('User has no valid FCM token');
  }

  try {
    const response = await admin.messaging().send({
      token: device.fcmToken,
      notification: {
        title: message.title,
        body: message.body
      }
    });

    console.log('Message sent:', response);
    return response;

  } catch (error) {
    console.error('FCM error:', error.code, error.message);

    // Check for invalid/unregistered token errors
    if (error.code === 'messaging/invalid-registration-token' ||
        error.code === 'messaging/registration-token-not-registered') {

      console.log('Marking token as invalid:', device.fcmToken);

      // Mark as invalid instead of deleting (for auditing)
      await db.userDevice.update({
        where: { id: device.id },
        data: {
          fcmTokenInvalidatedAt: new Date(),
          fcmTokenInvalidReason: error.code
        }
      });

      // Notify client to request new token
      // (could send another message or return error response)
    }

    throw error;
  }
}

For batch sends to multiple tokens:

javascript
async function sendBulkNotification(userIds, message) {
  const devices = await db.userDevice.findMany({
    where: {
      userId: { in: userIds },
      fcmTokenInvalidatedAt: null
    }
  });

  const tokens = devices.map(d => d.fcmToken);

  const response = await admin.messaging().sendEachForMulticast({
    tokens,
    notification: {
      title: message.title,
      body: message.body
    }
  });

  console.log('Batch send results:');
  console.log(`Successes: ${response.successCount}`);
  console.log(`Failures: ${response.failureCount}`);

  // Process failures and remove invalid tokens
  const tokensToInvalidate = [];

  response.responses.forEach((resp, idx) => {
    if (!resp.success) {
      const error = resp.error;
      console.error(`Token ${idx} failed:`, error.code, error.message);

      if (error.code === 'messaging/invalid-registration-token' ||
          error.code === 'messaging/registration-token-not-registered') {
        tokensToInvalidate.push({
          token: tokens[idx],
          deviceId: devices[idx].id,
          errorCode: error.code
        });
      }
    }
  });

  // Update invalid tokens in database
  for (const item of tokensToInvalidate) {
    await db.userDevice.update({
      where: { id: item.deviceId },
      data: {
        fcmTokenInvalidatedAt: new Date(),
        fcmTokenInvalidReason: item.errorCode
      }
    });
  }

  console.log(`Invalidated ${tokensToInvalidate.length} tokens`);
  return response;
}
5Implement token refresh on the client side monthly

Firebase recommends refreshing tokens at least once per month to maintain an up-to-date token store.

javascript
// Web - Refresh token monthly
const THIRTY_DAYS = 30 * 24 * 60 * 60 * 1000;

async function refreshFCMTokenIfNeeded() {
  const lastRefresh = localStorage.getItem('fcmTokenLastRefresh');
  const now = Date.now();

  // Refresh if never done or older than 30 days
  if (!lastRefresh || (now - parseInt(lastRefresh)) > THIRTY_DAYS) {
    try {
      const messaging = getMessaging();
      const token = await getToken(messaging, {
        vapidKey: 'YOUR_VAPID_KEY'
      });

      if (token) {
        await sendTokenToServer(token);
        localStorage.setItem('fcmTokenLastRefresh', now.toString());
        console.log('Token refreshed successfully');
      }
    } catch (error) {
      console.error('Failed to refresh token:', error);
    }
  }
}

// Call on app load
document.addEventListener('DOMContentLoaded', refreshFCMTokenIfNeeded);

// Also refresh on visibility change (user returns to app)
document.addEventListener('visibilitychange', () => {
  if (!document.hidden) {
    refreshFCMTokenIfNeeded();
  }
});
kotlin
// Android - Refresh token monthly
fun refreshFCMTokenIfNeeded(context: Context) {
  val prefs = context.getSharedPreferences("fcm_prefs", Context.MODE_PRIVATE)
  val lastRefresh = prefs.getLong("lastRefresh", 0)
  val thirtyDaysMs = 30 * 24 * 60 * 60 * 1000L

  if (System.currentTimeMillis() - lastRefresh > thirtyDaysMs) {
    FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
      if (task.isSuccessful) {
        val token = task.result
        Log.d(TAG, "Token refreshed: $token")

        sendTokenToServer(token)

        prefs.edit().putLong("lastRefresh", System.currentTimeMillis()).apply()
      }
    }
  }
}

// Call in Activity.onCreate() or Service
override fun onCreate() {
  super.onCreate()
  refreshFCMTokenIfNeeded(this)
}

Advanced notes

Token validity windows: FCM doesn't provide a guaranteed time window for token validity, but Firebase's best practices recommend treating tokens as stale after 2 months of inactivity and definitely invalid after 270 days (for Android). Implement a two-pronged approach: (1) Remove stale tokens proactively based on timestamp, and (2) clean up invalid tokens reactively when send attempts fail.

Handling token rotation: FCM may rotate tokens without warning. Implement a listener on the client side that fires whenever a new token is generated, and ensure the client immediately sends the new token to your server. This forms a self-healing system where stale tokens are naturally replaced.

Multi-device users: Users often have multiple devices (phone, tablet, web). Store tokens separately per device and platform, and implement cleanup to handle when a user removes a device. Don't assume a user has only one valid token.

Development vs. production tokens: Tokens generated against your development Firebase project cannot be used with your production Firebase project's credentials, and vice versa. Always ensure your backend credentials match the project where tokens were generated. Use environment-specific configuration.

Silent notification edge case: There's a known issue where FCM returns "invalid-registration-token" for valid tokens when sending iOS silent (APNs-only) notifications. If you encounter this with genuinely valid tokens on iOS, try including a notification payload instead of sending data-only or APNs silent notifications.

Rate limiting recovery: If you receive many invalid token errors in a short period, it may indicate you're sending to a large batch of stale tokens. Rather than retrying immediately, implement exponential backoff or batch your sends to avoid hitting FCM rate limits while cleaning up your token database.

Frequently asked questions

What does "messaging/invalid-registration-token" mean?
The "messaging/invalid-registration-token" error indicates that the registration token provided to Firebase Cloud Messaging (FCM) is not recognized as a valid, active FCM token. FCM registration tokens are unique identifiers that allow your backend server to send push notifications to specific devices. This error is different from "token format incorrect" - the token string itself may be properly formatted, but FCM considers it invalid because: - The token has expired (FCM marks tokens as invalid after 270 days of inactivity on Android) - The app that generated the token was uninstalled - The app was updated but not configured to receive messages - The APNS token on iOS was reported as invalid by the APNS Feedback Service - The device deleted its Instance ID - The user cleared the app data - The token was never properly registered with FCM in the first place When this error occurs, FCM returns HTTP status 400 with error code "INVALID_ARGUMENT", indicating the token should no longer be used to send messages.
How do I fix "messaging/invalid-registration-token"?
This error occurs when Firebase Cloud Messaging rejects a registration token because it is invalid, expired, unregistered, or no longer recognized by FCM. The fix involves validating tokens, removing stale tokens, refreshing tokens on the client side, and implementing proper token lifecycle management.
What causes "messaging/invalid-registration-token"?
Token has expired from 270+ days of inactivity (especially on Android) User uninstalled and reinstalled the app without updating your server's token store Device cleared app data or uninstalled the app but your database still contains the old token
Is the "messaging/invalid-registration-token" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading