question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Service Worker] Can't update sw if in SAFE_MODE

See original GitHub issue

I’m submitting a…


[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report  
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior

When the service worker is installed / initialized the first time, it fetches the ngsw.json. If the content of ngsw.json is not an valid json the sw goes into SAFE_MODE:

https://github.com/angular/angular/blob/c8a1a14b87e5907458e8e87021e47f9796cb3257/packages/service-worker/worker/src/driver.ts#L320-L325

From thereon it is impossible to update the service worker. If you call SwUpdate.checkForUpdate() it never resolves or rejects and no new fetch to ngsw.json is performed due to the fact that messages are ignored in SAFE_MODE:

https://github.com/angular/angular/blob/c8a1a14b87e5907458e8e87021e47f9796cb3257/packages/service-worker/worker/src/driver.ts#L189-L193

Replacing the wrong ngsw.json with the correct one does only resolve this issue if:

  • the service worker is unregistered (if ngsw.json did not contain json. for example it contains html)
  • or the sw is unregistered and the cache is cleared (if ngsw.json did contain a json. ex: { "test": 123 }). This also triggers the following error: Error: Invariant violated (initialize): latest hash null has no known manifest

This issue occurred on our firebase hosted app. It seems a cache sometimes returns a html page with a 2xx status instead of the ngsw.json and broke our service worker. We also needed to clear the cache and unregister the service worker on some mobile clients. It might be that firebase sends sometimes a wrong json file or there might be another way to lock the service worker in the SAFE_MODE with latest hash null error.

Expected behavior

  • It should be possible to update the sw with SwUpdate.checkForUpdate() when the sw is in SAFE_MODE
  • Maybe the sw should try to refetch the ngsw.json? I’m not sure when and if this would be the appropriated way to handle this issue.

Minimal reproduction of the problem with instructions

Repo: https://github.com/sean-nicholas/test-angular-service-worker

  • run npm run build
  • cd into `dist``
  • change the content of ngsw.json to
    • For non json case: asdjknkfdnjgdfkaslkdm
    • For json case: { "test": 123 }
  • run http-server (or something similar) in dist folder
  • goto localhost in incognito mode
  • you get the error
    • For non json case: Unexpected token a in JSON at position 0
    • For json case: TypeError: Cannot convert undefined or null to object
  • sw installation fails and sw goes into SAFE_MODE
  • reload & press the Check for SW Update Button
  • Checking will stay true and not fall back to false after a few ms
  • Replace the content of ngsw.json with the correct data

For non json case:

  • Unregister the sw & reload -> it works again

For json case:

  • Unregister the sw & reload
  • Error: Error: Invariant violated (initialize): latest hash null has no known manifest occures
  • Check for SW Update seems to work but if you reload it fails (does not resolve) again
  • Clear the cache, unregister the sw & reload -> it works again

What is the motivation / use case for changing the behavior?

The service worker should not lock itself into a state were it can not be updated anymore.

Environment


"@angular/animations": "^5.2.4",
"@angular/cdk": "^5.2.0",
"@angular/common": "^5.2.4",
"@angular/compiler": "^5.2.4",
"@angular/core": "^5.2.4",
"@angular/forms": "^5.2.4",
"@angular/http": "^5.2.4",
"@angular/material": "^5.2.0",
"@angular/platform-browser": "^5.2.4",
"@angular/platform-browser-dynamic": "^5.2.4",
"@angular/router": "^5.2.4",
"@angular/service-worker": "^5.2.4"

Browser:
(Only tested in)
- [x] Chrome (desktop) version 64.0.3282.140
- [x] Chrome (Android) version 64.0.3282.137
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
 

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:2
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

5reactions
k-schneidercommented, Apr 17, 2018

I was just hit by this on my dev machine and had a hell of a time figuring out what happened. Unregistering the service worker wasn’t enough… had to unregister AND clear my cache in Chrome. If this were to ever affect an end user they wouldn’t stand a chance.

3reactions
petivagyok16commented, Feb 19, 2018

Im experiencing the same issue. swUpdate.checkForUpdate() promise never gets resolved/rejected, so that now i cannot trigger manually the refreshing in my app.

  • TLDR: Everything works fine, if i close chrome devtools! Opened devtools screws up service worker update mechanism. Check if you can manage to work sw update after closing devtools! Hope this helps

My logic looks like this:

public checkUpdates() {

    this.swUpdate$ = this.swUpdate.available.subscribe(event => {

      console.log('[App] Update available: current version is', event.current, 'available version is', event.available);
      if (event.current.hash !== event.available.hash) {
        const snackbarRef = this.snackbar.open('New version available!', 'Refresh');

        snackbarRef.onAction().pipe(take(1)).subscribe(() => {
          this.winRef.nativeWindow.location.reload();
        });
      } else {
        this.snackbar.open('Your version is the newest!');
      }

    });

    this.activateUpdate$ = this.swUpdate.activated.subscribe(event => {
      console.log('[App] Update activated: old version was', event.previous, 'new version is', event.current);
    });

  }

  public checkForUpdate() {
    console.log('[App] checkForUpdate started');
    this.swUpdate.checkForUpdate()
      .then(() => {
        console.log('[App] checkForUpdate completed');
      })
      .catch(err => {
        console.error(err);
      });
  }

  public activateUpdate() {
    console.log('[App] activateUpdate started');
    this.swUpdate.activateUpdate()
      .then(() => {
        console.log('[App] activateUpdate completed');
        this.winRef.nativeWindow.location.reload();
      })
      .catch(err => {
        console.error(err);
      });
  }

In this way i can make a button in my app which can be tapped by the user for check updates checkForUpdates() and it triggers the this.swUpdate.available.subscribe(event => { ... } which will open a snackbar. But currently its not possible due to the never resolving/rejecting promise. Am i right?

UPDATE: Everything works fine, if i close chrome devtools! Opened devtools screws up service worker update mechanism. Check if you can manage to work sw update after closing devtools! Hope this helps

Read more comments on GitHub >

github_iconTop Results From Across the Web

Angular service worker is in SAFE_MODE - Stack Overflow
I have tried selecting 'Update on reload' which fixes the problem temporarily. Same error shows up again after I unselect it. Screenshot2. In ......
Read more >
MV3 service worker broken after auto-update - Google Groups
The only two ways to fix the service worker are 1) to push another update that overwrites the "bad" update (it's odd the...
Read more >
Using Service Workers - Web APIs | MDN
If your service worker has previously been installed, but then a new version of the worker is available on refresh or page load,...
Read more >
Service worker communication - Angular
It's possible to ask the service worker to check if any updates have been deployed to the server. The service worker checks for...
Read more >
Chromium Docs - Service Worker Security FAQ
Can iframes register Service Workers? Why doesn't Chrome prompt the user before registering a Service Worker? What if I don't want any SWs?...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found