Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firebase Cloud Messaging getToken hangs forever on web #8754

Open
liezl200 opened this issue Feb 3, 2025 · 4 comments
Open

Firebase Cloud Messaging getToken hangs forever on web #8754

liezl200 opened this issue Feb 3, 2025 · 4 comments

Comments

@liezl200
Copy link

liezl200 commented Feb 3, 2025

Operating System

MacOS Sonoma 14.4.1

Environment (if applicable)

Chrome 132.0.6834.160 (Official Build) (arm64)

Firebase SDK Version

8.10.1

Firebase SDK Product(s)

Messaging

Project Tooling

React app (nextjs)
I also tried 9.0.0 on my local dev machine with localhost

Detailed Problem Description

The last known time this getToken code path worked correctly in my production environment was 1pm EST today. Around 4pm EST I noticed FCM was throwing "Unknown token" errors when trying to push notifications to my test accounts. Thinking I could reset the permission, I started trying to Reset permission then Allow permission, but now getToken is hanging forever and I can't register any more FCM tokens

Steps and code to reproduce issue

try {
const msg = await messaging()
if (!msg) {
console.error('Firebase messaging is not supported or failed to initialize')
return
}
console.log('Firebase messaging initialized successfully')

// Register service worker
if ('serviceWorker' in navigator) {
  try {
    console.log('Registering service worker...')
    const registration = await navigator.serviceWorker.register('/firebase-messaging-sw.js')
    console.log('Service worker registered successfully:', registration)

    // Wait for the service worker to be ready
    await navigator.serviceWorker.ready
    console.log('Service worker is ready')

  } catch (error) {
    console.error('Failed to register service worker:', error)
    return
  }
} else {
  console.error('Service workers are not supported in this browser')
  return
}

try {
  console.log('Attempting to get FCM token...')
  
  // Add a timeout to detect hangs
  const tokenPromise = getToken(msg, { vapidKey: VAPID_KEY })
  const timeoutPromise = new Promise((_, reject) => 
    setTimeout(() => reject(new Error('getToken timed out after 10s')), 10000)
  )

  const fcmToken = await Promise.race([tokenPromise, timeoutPromise])
    .catch(error => {
      console.error('Error in getToken:', error)
      throw error
    })
@liezl200 liezl200 added new A new issue that hasn't be categoirzed as question, bug or feature request question labels Feb 3, 2025
@google-oss-bot
Copy link
Contributor

I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.

@jbalidiong jbalidiong added api: messaging needs-attention and removed needs-triage new A new issue that hasn't be categoirzed as question, bug or feature request labels Feb 4, 2025
@dlarocque
Copy link
Contributor

Hi @liezl200, I am unable to reproduce this. To help us identify the source of this issue, could you please

  1. Remove the custom service worker registration at the top of the file. getToken() will register the firebase-messaging-sw.js by default. Manually registering the default service worker may cause unexpected issues.
  2. Share any errors you're seeing in the browser console.
  3. Identify and share exactly which line in the SDK is causing the thread to hang. This would be very helpful.

I also recommend upgrading to the latest version of the Firebase JS SDK (11.2.0) to confirm that this issue has not already been fixed.

@liezl200
Copy link
Author

liezl200 commented Feb 4, 2025

I've updated to 11.2.0 but it's still hanging

package.json:

    "firebase": "^11.2.0",
    "firebase-admin": "^11.2.0",

I used debugger; and tried to step into getToken but despite allowing the service worker to register (even tried on a new Chrome profile) and then setting breakpoints here I couldn't see where it "goes"

  1. https://www.gstatic.com/firebasejs/installations/src/api/get-token.ts > getToken
  2. https://www.gstatic.com/firebasejs/messaging/src/api/getToken.ts > getToken
  3. https://www.gstatic.com/firebasejs/messaging/src/internals/token-manager.ts > getTokenInternal

** How can I figure out which line in the Firebase SDK it's actually getting stuck in during the call to getToken? Any recommendations for where to set some breakpoints? **
My next attempts I'll probably try a new repo with the example project with FCM from Youtube, and other browsers and devices.

I did see one (seemingly flaky error) but can't reliably reproduce this

webchannel_blob_es2018.js:79 
        
        
       GET https://firestore.googleapis.com/google.firestore.v1.Firestore/Listen/channel?gsessionid=RKTz0Nmny5EM9_ypnyHHsxXrQjaXEms98yBaMM8SGxQ&VER=8&database=projects%2Fbondi-web-app%2Fdatabases%2F(default)&RID=rpc&SID=icVHh9LVy2nqAwwKFrgmmQ&AID=8&CI=0&TYPE=xmlhttp&zx=gt5rl7ctjsca&t=1 404 (Not Found)
h.send @ webchannel_blob_es2018.js:79
h.ea @ webchannel_blob_es2018.js:87
Jb @ webchannel_blob_es2018.js:57
fd @ webchannel_blob_es2018.js:103
h.Fa @ webchannel_blob_es2018.js:102
Da @ webchannel_blob_es2018.js:41
Promise.then
x @ webchannel_blob_es2018.js:41
ec @ webchannel_blob_es2018.js:101
Ub @ webchannel_blob_es2018.js:104
M.Y @ webchannel_blob_es2018.js:61
M.ca @ webchannel_blob_es2018.js:57
ab @ webchannel_blob_es2018.js:52
F @ webchannel_blob_es2018.js:50
Wc @ webchannel_blob_es2018.js:89
h.bb @ webchannel_blob_es2018.js:88
h.Ea @ webchannel_blob_es2018.js:88
Lc @ webchannel_blob_es2018.js:84
Mc @ webchannel_blob_es2018.js:83
h.Pa @ webchannel_blob_es2018.js:82
Promise.then
Nc @ webchannel_blob_es2018.js:82
h.Pa @ webchannel_blob_es2018.js:82
Promise.then
Nc @ webchannel_blob_es2018.js:82
h.Pa @ webchannel_blob_es2018.js:82Understand this errorAI
index.esm2017.js:85 [2025-02-04T21:29:47.285Z]  @firebase/firestore: Firestore (11.2.0): WebChannelConnection RPC 'Listen' stream 0x536a58fe transport errored: jd {type: 'c', target: Y, g: Y, defaultPrevented: false, status: 1}

Additional context

I've removed the extra code that registers service workers. I can tell that getToken does successfully register the sw because I tried on a brand new Chrome profile while using Chrome debugger and could see the sw register.

For the below, I have tried my actual VAPID KEY and also intentionally fudged it to see if it would non-silently fail, and getToken actually did fail / didn't hang when I intentionally used the wrong one

import { messaging } from './firebase'
import { getToken, onMessage } from 'firebase/messaging'
import { deviceApi } from '@/store/apis/deviceApi'

const VAPID_KEY =
  'xyz'

// Checks if `Notification` is available
const isNotificationSupported = () =>
  typeof window !== 'undefined' && 'Notification' in window

export async function requestNotificationsPermissions(
  uid: string
): Promise<boolean> {
  console.log('Requesting notifications permission...')
  if (!isNotificationSupported()) {
    console.error('Notifications are not supported in this environment.')
    return false
  }
  const permission = await Notification.requestPermission()

  if (permission === 'granted') {
    console.log('Notification permission granted.')
    await saveMessagingDeviceToken(uid)
    return true
  } else {
    console.log('Unable to get permission to notify.')
    return false
  }
}

// Saves the messaging device token to our backend database via API
async function saveMessagingDeviceToken(uid: string) {
  console.log('Saving messaging device token...')

  try {
    const msg = await messaging()
    if (!msg) {
      console.error(
        'Firebase messaging is not supported or failed to initialize'
      )
      return
    }

    console.log('got msg')

    const fcmToken = await getToken(msg, { vapidKey: VAPID_KEY })
    console.log('finished getToken')
    if (fcmToken) {
      console.log('Got FCM device token:', fcmToken)

      // Save device token using deviceApi
      await deviceApi.registerToken(uid, fcmToken, 'web')

      // Set up foreground message handler
      onMessage(msg, (message) => {
        console.log(
          'New foreground notification from Firebase Messaging!',
          message.notification
        )
        if (isNotificationSupported() && message.notification?.title) {
          new Notification(message.notification.title, {
            body: message.notification?.body || '',
          })
        }
      })
    } else {
      // Need to request permissions to show notifications.
      requestNotificationsPermissions(uid)
    }
  } catch (error) {
    console.error('Unable to save messaging token.', error)
  }
}

export function getNotificationPermissionStatus(): NotificationPermission | null {
  if (!isNotificationSupported()) {
    console.error('Notifications are not supported in this environment.')
    return null
  }
  return Notification.permission
}

firebase-messaging-sw.js

/**
 * @license
 * Copyright 2022 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


console.log('from worker 444')
importScripts(
  'https://www.gstatic.com/firebasejs/11.2.0/firebase-app-compat.js'
)
importScripts(
  'https://www.gstatic.com/firebasejs/11.2.0/firebase-messaging-compat.js'
)

const firebaseConfig = {
  apiKey: 'xyz',
  authDomain: 'abc.firebaseapp.com',
  projectId: 'abc',
  storageBucket: 'abc.appspot.com',
  messagingSenderId: 'abc',
  appId: 'abc',
}
console.log('from worker with firebase config', firebaseConfig)
firebase.initializeApp(firebaseConfig)

console.log('done init app from worker with firebase config', firebaseConfig)
// Retrieve firebase messaging
const messaging = firebase.messaging()
console.log('done init messaging from worker')
messaging.onBackgroundMessage((payload) => {
  console.log('Received background message ', payload)

  const notificationTitle = payload.notification.title
  const notificationOptions = {
    body: payload.notification.body,
  }

  self.registration.showNotification(notificationTitle, notificationOptions)
})

Note I had to use -compat because I was getting Network error trying to directly importScripts 'https://www.gstatic.com/firebasejs/11.2.0/firebase-app.js'

I see everything printed out, including the "got msg" console.log line that I put right after const msg = await messaging() and before the call to getToken

@dlarocque
Copy link
Contributor

@liezl200 Thanks for sharing more information. It's interesting that the service worker is registered, but getToken still hangs. To see exactly where it hangs in a debugger, you should be able to put a breakpoint on getToken and step through from there. If your code is hitting getTokenInternal then the service worker and vapid key registration were successful. You mentioned that this error only suddenly started happening after some time. Could you share those errors? They may help me create an app that reproduces the error.

I believe the Firestore error you shared is unrelated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants