firebase-js-sdk icon indicating copy to clipboard operation
firebase-js-sdk copied to clipboard

getToken throw error : DOMException: Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker

Open EricaLi123 opened this issue 8 months ago • 13 comments

Operating System

win 10

Browser Version

chrome 118.0.5993.71 (Official Build) (64-bit)

Firebase SDK Version

10.4.0

Firebase SDK Product:

Messaging

Describe your project's tooling

https://www.gstatic.com/firebasejs/10.4.0/firebase-app-compat.js https://www.gstatic.com/firebasejs/10.4.0/firebase-messaging-compat.js

Describe the problem

  1. clear cookie image

  2. when open my web site for the first time, getToken throw the following error【NG】 image

  3. when open my web site for the second time or refresh the tab, getToken works fine. image

Steps and code to reproduce issue

return this.messaging.getToken({
            vapidKey : this.vapidKey,
        }).then((currentToken) => {
            if (currentToken) {
                console.log(currentToken);
                return currentToken;
            } else {
                console.log('No Instance ID token available. Request permission to generate one.');
                return null;
            }
        }).catch((err) => {
            console.error(err);
        });

EricaLi123 avatar Oct 11 '23 09:10 EricaLi123

having the same issue. it seems the service worker file firebase-messaging-sw.js is installed when called getToken() for the first time, after refreshing and calling getToken again it then works..

duc-gp avatar Oct 14 '23 22:10 duc-gp

I have similar issue as well. Reproducible in chrome 118 and safari. Seems to be critical, I haven't use the API before chrome 118, so can't say if it is a regression. Is there any insight here from the team @jbalidiong ?

baryosef-loops avatar Oct 19 '23 09:10 baryosef-loops

So I took this temporary approach to the problem.

this.messaging
      .getToken({
          vapidKey : this.vapidKey,
      }).catch((err) => {
          // https://github.com/firebase/firebase-js-sdk/issues/7693
          // 如果 getToken 时是还没注册 firebase-messaging-sw.js,就会报错如下,再次执行 getToken 就好了
          const error = "AbortError: Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker";
          if (err.toString() === error) {
              return this.messaging.getToken({
                  vapidKey : this.vapidKey,
              });
          } else {
              throw err;
          }
      })
      .then((currentToken) => {
          if (currentToken) {
              console.log(currentToken);
              return currentToken;
          } else {
              console.log(
                  'No Instance ID token available. Request permission to generate one.'
              );
              return null;
          }
      })
      .catch((err) => {
          console.error(err);
      });

I look forward to letting me know when this issue is completely fixed

EricaLi123 avatar Oct 26 '23 04:10 EricaLi123

Facing same issue with latest firebase 10.5.0. Please help with the fix.

dpeese avatar Oct 26 '23 16:10 dpeese

@dpeese this solution worked for me

So I took this temporary approach to the problem.

this.messaging
      .getToken({
          vapidKey : this.vapidKey,
      }).catch((err) => {
          // https://github.com/firebase/firebase-js-sdk/issues/7693
          // 如果 getToken 时是还没注册 firebase-messaging-sw.js,就会报错如下,再次执行 getToken 就好了
          const error = "AbortError: Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker";
          if (err.toString() === error) {
              return this.messaging.getToken({
                  vapidKey : this.vapidKey,
              });
          } else {
              throw err;
          }
      })
      .then((currentToken) => {
          if (currentToken) {
              console.log(currentToken);
              return currentToken;
          } else {
              console.log(
                  'No Instance ID token available. Request permission to generate one.'
              );
              return null;
          }
      })
      .catch((err) => {
          console.error(err);
      });

I look forward to letting me know when this issue is completely fixed

ejirocodes avatar Nov 07 '23 07:11 ejirocodes

Running into the same issue. So is the recommended solution to just retry if it fails?

pcriadoperez avatar Dec 01 '23 18:12 pcriadoperez

register Firebase service worker before getToken: navigator.serviceWorker.register("/firebase-messaging-sw.js", { scope: "/firebase-cloud-messaging-push-scope" })

benixal avatar Dec 11 '23 10:12 benixal

Hi bro. I am also facing a similar issue as you. And I fix it as follows.

const getOrRegisterServiceWorker = () => {
  if ('serviceWorker' in navigator) {
   return window.navigator.serviceWorker
     .getRegistration('/firebase-cloud-messaging-push-scope')
     .then((serviceWorker: TODO) => {
       if (serviceWorker){
         return serviceWorker;
       } 
       return window.navigator.serviceWorker.register('/firebase-messaging-sw.js')
       .then((serviceWorker: TODO)=>{
             console.log("success registering SW");
       }).catch((err)=>{
         console.log("registering failed",err);
       });
     }
 )}
 throw new Error('The browser doesn`t support service worker.');
};


export const requestToken = async () => {
  let currentToken = "";
  try {
    const serviceWorkerRegistration = await getOrRegisterServiceWorker();
    currentToken = await getToken(messaging, {
      vapidKey: key,
      serviceWorkerRegistration
    });
  } catch (error) {
    console.log("An error occurred while retrieving token. ", error);
  }
  return currentToken;
};

KhanhKitin avatar Dec 20 '23 10:12 KhanhKitin

Solved by calling getToken() twice. The docs are confusing and outdated.

What should be the name of the service worker? firebase-messaging-sw.js (as shown here) or service-worker.js (as shown here)

What version should I use for the Web namespaced API? 8.10.1 or the latest one?

kedniko avatar Dec 23 '23 12:12 kedniko

  1. Create a service worker
  2. Register it
  3. Then use serviceWorkerRegistration option to pass it to the getToken

https://github.com/benixal/FCM-Web-Notify-Example/blob/main/index.html#L35

https://www.youtube.com/watch?v=iz5arafmatc&t=6m12s

https://firebase.google.com/docs/reference/js/messaging_.gettokenoptions.md#gettokenoptionsserviceworkerregistration

benixal avatar Jan 11 '24 06:01 benixal

I resolve it by waiting for activated state of ServiceWorker.

const getFBToken = (
    m: Messaging,
    serviceWorkerRegistration: ServiceWorkerRegistration
): Promise<string> | undefined => {
    let sw: ServiceWorker | undefined;
    if (serviceWorkerRegistration.installing) {
        sw = serviceWorkerRegistration.installing;
    } else if (serviceWorkerRegistration.waiting) {
        sw = serviceWorkerRegistration.waiting;
    } else if (serviceWorkerRegistration.active) {
        sw = serviceWorkerRegistration.active;
    }
    if (sw) {
        if (sw.state === 'activated') {
            return getToken(m, {
                vapidKey: import.meta.env.VITE_PUSH_PUBLIC_KEY,
                serviceWorkerRegistration
            });
        }
        const deferred = new Deferred<string>();
        sw.addEventListener('statechange', async (e) => {
            if ((e.target as ServiceWorker)?.state === 'activated') {
                const token = await getToken(m, {
                    vapidKey: import.meta.env.VITE_PUSH_PUBLIC_KEY,
                    serviceWorkerRegistration
                });
                deferred.resolve(token);
            }
        });
        return deferred.promise;
    }
    return undefined;
};

dyabol avatar Apr 25 '24 12:04 dyabol

I resolved it like this

export async function generateToken({ subscribeTopic }: { subscribeTopic: (token: string) => void }) { try { const messaging = await getMessaging() // requesting permission using Notification API const permission = await Notification.requestPermission() if (!messaging) { return } if (permission !== 'granted') { return } if (!navigator.serviceWorker) { return } const serviceWorkerRegistration = await navigator.serviceWorker.ready if (serviceWorkerRegistration.active?.state === 'activated') { const token = await getToken(messaging, { vapidKey: VITE_FIREBASE_VAPID_KEY, serviceWorkerRegistration }) /* eslint-disable no-console */ console.log('[generateToken] token: ', token) subscribeTopic(token) } } catch (error) { console.log('[generateToken]:: error occur generateToken', error) } }

Danhhan avatar May 10 '24 04:05 Danhhan