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

Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker #7575

Open
2manoj1 opened this issue Aug 21, 2023 · 59 comments

Comments

@2manoj1
Copy link

2manoj1 commented Aug 21, 2023

Operating System

MacOS

Browser Version

All browser

Firebase SDK Version

10.2.0

Firebase SDK Product:

Messaging

Describe your project's tooling

Nextjs 13 with Page setup.
Example Repo -> https://github.com/2manoj1/nextjs-firebase-example/tree/main

Describe the problem

Same problem as #5797
Sometimes calling messaging getToken returns the error: Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker.
It seems to occur on the first page load and clear storage with unregister sw, when the user refreshes the notifications work and there's no error anymore.

Screenshot 2023-08-21 at 1 45 33 PM

Steps and code to reproduce issue

@2manoj1 2manoj1 added new A new issue that hasn't be categoirzed as question, bug or feature request question labels Aug 21, 2023
@jbalidiong jbalidiong added needs-attention and removed new A new issue that hasn't be categoirzed as question, bug or feature request labels Aug 21, 2023
@2manoj1
Copy link
Author

2manoj1 commented Aug 21, 2023

After remove useCallback and made some changes check its working. 2manoj1/nextjs-firebase-example@0f193f5

@2manoj1 2manoj1 closed this as completed Aug 21, 2023
@2manoj1
Copy link
Author

2manoj1 commented Aug 21, 2023

Screenshot 2023-08-21 at 2 23 42 PM

Why this occurred now. any config changes require? How fix this issue?

@2manoj1 2manoj1 reopened this Aug 21, 2023
@jbalidiong
Copy link
Contributor

Hi @2manoj1, thanks for reporting this issue. I was able to reproduce the behavior you mentioned. Let me check what we can do for this issue or bring someone here that can provide more context about it. I’ll update this thread if I have any information to share.

@2manoj1
Copy link
Author

2manoj1 commented Aug 22, 2023

This issue still coming in first time. Also clear cache way. My workaround not working. Look like service worker firebase having issues.

@2manoj1
Copy link
Author

2manoj1 commented Aug 25, 2023

@jbalidiong any solutions? Any workaround how to fix this issue. In Production also coming this issue.

@jbalidiong
Copy link
Contributor

@2manoj1, apologies for the delay. I have discussed this with our FCM team and this is working as intended. The 404 that you've received from this screenshot is due to the indexDB being cleared and then there will be no token(s) to be deleted. With your app, I experience the same behavior. However, after receiving the warning, a new token will be created. Is this not the same as yours? Are you receiving any other errors aside from the previous one or you are not able to receive a new token?

@2manoj1
Copy link
Author

2manoj1 commented Aug 25, 2023

@jbalidiong
This issue still persist. On new device try to getToken first time. Its error coming and token is null.

Also I tried clear storage and unregister service worker or clear everything. Its reproducible. Without 2 refresh this cause issue.

Look like before ready service worker calling. await swRegistration.serviceWorker.ready missing before call subscribe.

261962363-d01424c8-c42a-4786-8e63-515bcb1949aa

@zwu52
Copy link
Member

zwu52 commented Aug 30, 2023

I am unfamiliar w/ next but your repo doesn't seem to have a required firebase-messaging-sw.js file https://github.com/search?q=repo%3A2manoj1%2Fnextjs-firebase-example%20firebase-messaging-sw.js&type=code.

Per public doc https://firebase.google.com/docs/cloud-messaging/js/client#access_the_registration_token: "FCM requires a firebase-messaging-sw.js file. Unless you already have a firebase-messaging-sw.js file, create an empty file with that name and place it in the root of your domain before retrieving a token. You can add meaningful content to the file later in the client setup process".

(Also btw, you are leaking your api key in the repo shared. Maybe you'd like to obfuscate or hide it. )

@2manoj1
Copy link
Author

2manoj1 commented Aug 30, 2023

@zwu52 sw file already in public folder please check.
public/firebase-messaging-sw.js

API key not required to hide. Watch official firebase video. If I hide also SPA app expose in source. Don't worry about key.

  • FYI it's working only first time having issue. Which I raise here

@zwu52
Copy link
Member

zwu52 commented Aug 31, 2023

My hypothesis is some intricacies on how next loads scripts cause the incompatibilities between the SDK & the code.

I suspect it's not a race issue you suspected "Look like before ready service worker calling. await swRegistration.serviceWorker.ready missing before call subscribe." given the registration call is a blocking call here https://github.com/firebase/firebase-js-sdk/blob/master/packages/messaging/src/helpers/registerDefaultSw.ts#L27.

Another pointer to the loading of the sw path here https://github.com/firebase/firebase-js-sdk/blob/master/packages/messaging/src/helpers/registerDefaultSw.ts#L28. The SDK is expecting the sw script to live in a root directory.

Can you try to play around the SDK & figure out how to make it compatible?

@2manoj1
Copy link
Author

2manoj1 commented Aug 31, 2023

I am trying but not able to figure out how use my fork version.

@2manoj1
Copy link
Author

2manoj1 commented Sep 4, 2023

@jbalidiong are get chance to see this #7575 (comment) ?

@kessler428
Copy link

I have the same problem, but with the flutter package:

Screenshot_2023-09-06_at_10 08 01_PM

When I run the app for the first time that's when I get that error, but if I reload the permissions my app works fine, this is where the app fails:

Screenshot 2023-09-06 at 10 18 07 PM

I am following the process correctly, first I made the permissions request and then I got the token.

And well, this is a new error of my application, this application was working correctly, I did not change anything and now I have this error.

@2manoj1
Copy link
Author

2manoj1 commented Sep 8, 2023

Workaround - if fail call again get token. 3 Retry I did and that's way solve the fix

@dpeese
Copy link

dpeese commented Oct 26, 2023

Same issue here #7693

@FarzaneGhb
Copy link

i have the same issue.

I get this error: "Error: AbortError: Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker " when I run my Flutter app for the first time on Chrome browser, but if I restart the app or refresh the browser page, the error disappears.

is there any solution for that?

@mohamedamara1
Copy link

mohamedamara1 commented Dec 13, 2023

I noticed this happened when I used Chrome, I switched to Firefox and I didn't have it anymore with exactly the same code.

But after some code changes I made it work again in chrome, not even sure why exactly or how it got fixed.

@HusainPatel7
Copy link

i have the same issue.

I get this error: "Error: AbortError: Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker " when I run my Flutter app for the first time on Chrome browser, but if I restart the app or refresh the browser page, the error disappears.

is there any solution for that?
"I am also experiencing the same issue. Please let me know if anyone has found a solution for it."

@dyabol
Copy link

dyabol commented May 2, 2024

i have the same issue.
I get this error: "Error: AbortError: Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker " when I run my Flutter app for the first time on Chrome browser, but if I restart the app or refresh the browser page, the error disappears.
is there any solution for that?
"I am also experiencing the same issue. Please let me know if anyone has found a solution for it."

Try my solution here: #7693 (comment)

@ajmal-penny
Copy link

It can be fixed by waiting for the serviceWorker to be ready:

await navigator.serviceWorker.ready
const token = await getToken(options);

@DellaBitta
Copy link
Contributor

Hi @2manoj1,

Can you see if your issue is fixed by waiting for the server worker to full initialize, as suggested above by @dyabol and @ajmal-penny?

Thanks!

@2manoj1
Copy link
Author

2manoj1 commented Aug 29, 2024

@DellaBitta I work with workaround #7575 (comment)

#7575 (comment)

Tried that but no luck so I added 3 retry logic. I think this should be added in lib code level.

Was tried this before 2manoj1#1

@andynewman10
Copy link

andynewman10 commented Sep 2, 2024

@DellaBitta the proposed fix, await navigator.serviceWorker.ready, does not fix the problem.

I can confirm this, since I experienced the issue multiple times already, and yet again, with the above mentionned fix, it didn't work. When getToken() was called, even though I called await navigator.serviceWorker.ready just before, I did get the 'no service worker' error and had to try again twice to get the token.

I too, believed this would work and I actually thought the problem was fixed after maybe 20 or 30 tries, but the problem eventually showed up once again, meaning await navigator.serviceWorker.ready is not sufficient or reliable enough.

@andynewman10
Copy link

It can be fixed by waiting for the serviceWorker to be ready:

await navigator.serviceWorker.ready
const token = await getToken(options);

@ajmal-penny this is not sufficient to get rid of the error. You may still get 'no service worker' errors. I've launched hundreds of debug sessions the last few days, and this fix does not appear to be 100% reliable, I'm afraid.

@dyabol
Copy link

dyabol commented Sep 2, 2024

@DellaBitta Using await navigator.serviceWorker.ready is not sufficient nor did it work in my case. The "I hope it passes on the third try" solution is not acceptable for me. Based on what's in the SW documentation (https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/statechange_event) I find out what the state of the SW is, if it's not activated, I register the "statechange" event and wait until the SW is activated, then call getToken. See #7693 (comment) nothing magical

@andynewman10
Copy link

andynewman10 commented Sep 2, 2024

@dyabol thanks for the clarification. Are you calling the code shown in #7693 (comment):

  • before await navigator.serviceWorker.ready
  • after await navigator.serviceWorker.ready
  • you're not calling await navigator.serviceWorker.ready at all?

@dyabol
Copy link

dyabol commented Sep 2, 2024

@andynewman10 I use https://vite-pwa-org.netlify.app/frameworks/react to register SW in my project so I don't know if this library implements something similar, but I don't use await navigator.serviceWorker.ready in my code.

@andynewman10
Copy link

@dyabol I've implemented your method yesterday and launched debug sessions with it maybe 30-40 times. On one occasion, this morning, it did fail.

Again, this method is not reliable enough.

@dyabol
Copy link

dyabol commented Sep 3, 2024

@andynewman10 Do you have an example implementation or reproduced bug somewhere? I would be happy to help you, I have been using this solution in my application with 100% success for several months. Alternatively, if there is a flaw in the solution, I would like to know about it. Thx

@andynewman10
Copy link

@dyabol I'm using Flutter. I translated your code, but there still are (very rare) situations where this code ends up with a 'no service worker' issue:

Future<bool> waitServiceWorker() async {
  final swr = await web.window.navigator.serviceWorker.getRegistration().toDart;
  if (swr == null) {
    return false;
  }
  web.ServiceWorker? sw;
  if (swr!.installing != null) {
    sw = swr!.installing;
  } else if (swr!.waiting != null) {
    sw = swr!.waiting;
  } else if (swr!.active != null) {
    sw = swr!.active;
  }
  if (sw != null) {
    if (sw.state == 'activated') {
      return true;
    }
    var completer = Completer<bool>();
    sw.onstatechange.add((web.Event e) {
      if ((e.target as web.ServiceWorker).state == 'activated') {
        completer.complete(true);
      }
    }.toJS);
    await completer.future;
    await web.window.navigator.serviceWorker.ready.toDart;
    return true;
  }
  return false;
}

@dyabol
Copy link

dyabol commented Sep 5, 2024

@andynewman10 I have no experience with Flutter, but aren't "service worker not activated" and "no service worker" two different problems? Don't you rather have a problem somewhere in the SW registration?

@andynewman10
Copy link

@dyabol my apology, I meant 'no active service worker'. Sorry about this. I am checking if the exception string raised by FirebaseMessaging.instance.getToken contains 'no active service worker' and, if this is the case, I start again.

@andynewman10
Copy link

andynewman10 commented Sep 5, 2024

@dyabol the next time I experience the issue, I'll try to paste here logging information. I added log entries before and after getToken, when an exception is raised, and at various locations inside the above function.

@andynewman10
Copy link

I have another big issue with getToken - it sometimes takes 30+, up to 160 seconds to return a token, while I am developing over localhost. Have you observed that too? Not sure if this is linked yet but I am actively investigating. Will probably be worth another issue report. With the exact same Dart code, Android and iOS have zero problems, and I really mean zero.

@dyabol
Copy link

dyabol commented Sep 5, 2024

@dyabol I'm using Flutter. I translated your code, but there still are (very rare) situations where this code ends up with a 'no service worker' issue:

Future<bool> waitServiceWorker() async {
  final swr = await web.window.navigator.serviceWorker.getRegistration().toDart;
  if (swr == null) {
    return false;
  }
  web.ServiceWorker? sw;
  if (swr!.installing != null) {
    sw = swr!.installing;
  } else if (swr!.waiting != null) {
    sw = swr!.waiting;
  } else if (swr!.active != null) {
    sw = swr!.active;
  }
  if (sw != null) {
    if (sw.state == 'activated') {
      return true;
    }
    var completer = Completer<bool>();
    sw.onstatechange.add((web.Event e) {
      if ((e.target as web.ServiceWorker).state == 'activated') {
        completer.complete(true);
      }
    }.toJS);
    await completer.future;
    await web.window.navigator.serviceWorker.ready.toDart;
    return true;
  }
  return false;
}

Can't be a problem in this line?

final swr = await web.window.navigator.serviceWorker.getRegistration()

In my code, I pass the ServiceWorkerRegistration instance obtained during registration. See #7693 (comment)

@andynewman10
Copy link

andynewman10 commented Sep 5, 2024

In my code, I pass the ServiceWorkerRegistration instance obtained during registration. See #7693 (comment)

Are you getting different references? I'd be surprised if you are.

Flutter's Firebase implementation (Flutterfire) does not let me easily dig into the registration process.

@andynewman10
Copy link

Here is one typical log output, where it succeeds after the first attempt:

Obtaining FCM token
Service worker registration is in active state
Service worker is in activated state
awaiting .ready
Calling instance.getToken, attempt #0
getToken attempt succeeded after 118826 milliseconds
FCM token obtained after 1 attempt(s)

I'll post another log once I can reproduce our present issue - which is rare.

(Note the 118 seconds delay I got here, but that's another issue. In most cases, getToken completes in under 3 seconds.
Out of the maybe 1000+ (or is it 3000+) debug sessions I launched since I started to work on this project, I didn't get a delay a single time with the same Flutter code running on Android or iOS. The problem might of course come from the Flutter bridge ; or even my setup, but that's more unlikely).

@andynewman10
Copy link

@dyabol I confirm your method is not bullet proof. Just got the error this morning:

Obtaining FCM token
Service worker registration is in active state
Service worker is in activated state
Calling instance.getToken, attempt #0
getToken attempt failed after 481 milliseconds
Calling instance.getToken, attempt #1
getToken attempt failed after 1 milliseconds
Calling instance.getToken, attempt #2
getToken attempt failed after 1 milliseconds
Calling instance.getToken, attempt #3
getToken attempt failed after 12 milliseconds
Calling instance.getToken, attempt #4
getToken attempt succeeded after 3608 milliseconds
FCM token obtained after 5 attempt(s)

I am trying another attempt every time the 'no active service worker' error (and no other error) is raised.

@sanishmistry
Copy link

Does anyone know what causes this? I have had firebase messaging working on many websites for several years, and I've just noticed this issue is now happening?

@mdoumbouya117
Copy link

Make sure you are not using a truncated FCM_VAPID_KEY. Try to delete and regenerate a new one.

@nick-pereira
Copy link

I had a middleware to override my fetch calls to add tenantid querystring to the url.
Which was causing firebaseinstallations and fcmregistrations api calls to google fail. Skipping it fixed the issue.

@hoyyChoi
Copy link

I faced a similar issue, where errors occurred during the process. However, I noticed that when the page was refreshed after the error, the device token was successfully received. Based on this observation, I implemented the following logic:

I handled the issue by allowing up to 3 retry attempts when an error occurred during the request. This approach helped resolve the problem quickly after the initial error.

// Wait for the service worker registration to complete
await registerServiceWorker();
const token = await retryGetDeviceToken(3); // Retry up to 3 times

// Added retry logic for getDeviceToken
async function retryGetDeviceToken(retries: number): Promise<string> {
  try {
    return await getDeviceToken();
  } catch (error) {
    if (retries === 0) {
      console.error("Maximum retry attempts exceeded:", error);
      throw error;
    } else {
      console.warn(`Retrying getDeviceToken... Remaining attempts: ${retries}`);
      return retryGetDeviceToken(retries - 1);
    }
  }
}

@AbdulghaniHa
Copy link

If any wonders on how to reproduce the error on Mac (Safari):

  1. Safari => Settings => Privacy => Manage website data => Remove all
  2. Safari => Settings => Website => click on your website => Remove

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