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

Service worker Invariant violated (initialize): latest hash null #25611

Closed
dottodot opened this issue Aug 22, 2018 · 56 comments
Closed

Service worker Invariant violated (initialize): latest hash null #25611

dottodot opened this issue Aug 22, 2018 · 56 comments
Labels
area: service-worker Issues related to the @angular/service-worker package freq2: medium type: bug/fix
Milestone

Comments

@dottodot
Copy link

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[X] Bug report  
[ ] Performance issue
[ ] 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
[ ] Other... Please describe:

Current behavior

Firstly I'm unable to get the service worker to register using

 ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production })

I have to use the following in my main.ts

platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .then(() => {
    if ('serviceWorker' in navigator && environment.production) {
      navigator.serviceWorker.register('/ngsw-worker.js');
    }
  })

and when I test locally the service worker registers fine. But after I deploy to my server the service worker fails to register with the following error

ngsw-worker.js:2178 Uncaught (in promise) Error: Invariant violated (initialize): latest hash null has no known manifest
at Driver. (ngsw-worker.js:2178)
at Generator.next ()
at fulfilled (ngsw-worker.js:1755)

maybe this is why the recommended way to register the service worker fails, although unsure on that as I don't get any errors.

Expected behavior

The service worker was installed using angular cli and has been setup without any changes and is installed as per the documentation, however this doesn't work.

Minimal reproduction of the problem with instructions

As the issue can't be replicated locally there's little value in providing code. Need to understand why the same production build works locally but doesn't when deployed.

Environment


Angular CLI: 6.1.4
Node: 8.11.3
OS: darwin x64
Angular: 6.1.3
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, platform-server, router
... service-worker

Package                            Version
------------------------------------------------------------
@angular-devkit/architect          0.7.4
@angular-devkit/build-angular      0.7.4
@angular-devkit/build-optimizer    0.7.4
@angular-devkit/build-webpack      0.7.4
@angular-devkit/core               0.7.4
@angular-devkit/schematics         0.7.4
@angular/cdk                       6.4.6
@angular/cli                       6.1.4
@angular/material                  6.4.6
@angular/material-moment-adapter   6.4.6
@angular/pwa                       0.7.4
@ngtools/webpack                   6.1.4
@schematics/angular                0.7.4
@schematics/update                 0.7.4
rxjs                               6.2.2
typescript                         2.9.2
webpack                            4.9.2

Others:

@gkalpak
Copy link
Member

gkalpak commented Aug 22, 2018

Sorry, but it is not possible to investigate this without a reproduction 😞
Closing as non-actionable. Happy to re-open and investigate if you can provide a reproduction.

@gkalpak gkalpak closed this as completed Aug 22, 2018
@dottodot
Copy link
Author

Very helpful. So unless I can provide a replication there can be no discussion to what the problem is and the issue just get closed. No explanation as to the what would cause that error then as that would be helpful, or do we have to guess and hope it fixes itself.

@gkalpak
Copy link
Member

gkalpak commented Aug 23, 2018

Closing the issue doesn't mean there can be no discussion.

I have no idea what might be causing the error (because afaict that error should never happen 😳). It is not impossible that this is a browser bug. But we can't investigate without a reproduction 🤷‍♂️

Regarding the registration issue, my guess is that it is unrelated to the error. Possibly related to #20970 (I can't really know without...you guessed it...a reproduction 😁)

(Happy to continue the discussion below.)

@dottodot
Copy link
Author

I had recently noticed that I was still getting this issue on one of my machines and as a result the following update message was never triggered.

Once I'd completely cleared the browser cache on that machine the service worker no longer had the error and installed correctly. There must have been a bug in the service worker at some point which didn't get cleared in the updates. Thankfully the user base for this particular app is very small as wouldn't have been great trying to instruct a large number of users on how to fix it.

  ngOnInit() {
    if (this.swUpdate && this.swUpdate.isEnabled) {
      this.swUpdate.available.subscribe(event => {
        console.log('current version is', event.current);
        console.log('available version is', event.available);
        if (confirm('New version of admin available. Load New Version?')) {
          this.swUpdate.activateUpdate().then(() => window.location.reload());
        }
      });
    }
  }

@pleinonen
Copy link

I also got this very same error with latest Angular (7.2). Unfortunately it is very hard to reproduce as it just happened in one installation. After the error, SW seems to bail out without actually executing ngsw-worker.js so it's bit hard to debug what's going on. I wish SW would just clear all the caches when it crashes so it would hopefully recover from the error next time user visits the site.

@pleinonen
Copy link

After enabling 'Update on reload' in Chrome's service worker settings I was able to debug the issue. For some reason, in initialize() command const table = yield this.db.open('control'); would return empty object and hence bit later on, latest.latest; would equal to null. Because of this, this.versions.has(latest.latest) check would return null and 'Invariant violated (initialize)' exception was thrown. At this point I manually called this.cleanupCaches(); and this would fix the problem next time I reloaded the page.

Problem here is of course that I had to check that developer option to be able to execute the code so this won't fix problems when SW is in error state (I think). I hope this information could help someone who actually knows more about the internals of Angular SW worker.

@gkalpak
Copy link
Member

gkalpak commented Jan 16, 2019

@pleinonen, thx for providing extra info. If there is a problem reading latest from the control "table", the SW fetched and uses the latest hash. So, I still don't see how latest.latest could be null (unless we explicitly stored it as null (which again doesn't seem possible).

Did you by any chance manually looked at the contents of the control cache (before fixing the problem)?

@pleinonen
Copy link

@gkalpak Unfortunately I cannot reproduce problem anymore after using the cleanupCaches-trick above. Of several instance I have, error did happen only once. However, I do remember clear that when hitting the break point at exception, latest.latest was indeed null. Not 'undefined' or anything like that. It was null.

Everything else is bit vague I am afraid. I did peek 'manifest' and 'assignments' properties after this and they did not contain any sensible values either (empty object probably).

Finally, I the steps to reproduce were something like this:

  1. Push new version of app online (update from 6.1.3 -> 7.2.0) and few other vendor libs).
  2. I did refresh to browser with dev tools open and I saw 'Invariant violated (initialize)' exception on console log. Twice I believe and right after 'gsw.json?ngsw-cache-bust' or during that.
  3. I did check '.../ngsw/state' right after this and saw same exception on the log
  4. After this, SW would stay in error state no matter what.
  5. I did check the cache storage from dev tools and while I have ton of SW related entries there, I am pretty sure I would have noticed if entry 'ngsw:db:control' had been there during the error. If I have to guess it was either empty or missing but cannot say for sure.

Could it be that the control table can be corrupted in during the update?

@gkalpak
Copy link
Member

gkalpak commented Jan 17, 2019

Corruption might explain it. Maybe we should enter SAFE_MODE (but still allow scheduled tasks to complete) when initialization fails in onMessage() (like we do in handleFetch() for example).

@philipooo
Copy link

I see this error happening quite often. Here are some informations I collected from the debugger.

  1. initialize() is called
  2. const table = await this.db.open('control') contains {"table":"control","cache":{},"adapter":{}}
  3. After [manifests, assignments, latest] = ... the variables contain manifests = {}, assignments = {}, latest = {latest: null}
  4. catch (_) is never called
  5. this.latestHash = latest.latest; produces Uncaught (in promise) Error: Invariant violated (initialize): latest hash null has no known manifest at Driver.<anonymous> (ngsw-worker.js:2208) at Generator.next (<anonymous>) at fulfilled (ngsw-worker.js:1772)

Chrome 72.0.3626.109, Angular 7.0.4

@gkalpak
Copy link
Member

gkalpak commented Feb 18, 2019

Thx for the info, @philipooo. I think I can see a path that could lead to having {latest: null} in the cache now.

If the app sent a message to activate an update before running the SW initialization, then we could get a call chain like this:
-> driver.onMessage()
-> driver.handleMessage()
-> driver.clientUpdate()
-> driver.sync()
-> table.write() with latest: this.latestHash (where latestHash would still be null)

Not sure how that would happen, given that clients would not be notified about updates before initialization, but maybe it is worth ensuring that the Driver is initialized in driver.handledMessage(). Something like:

 private async handleMessage(msg: MsgAny&{action: string}, from: Client): Promise<void> {
+  if (this.initialized === null) {
+    this.initialized = this.initialize();
+  }
+  try {
+    await this.initialized;
+  } catch (e) {
+    this.state = DriverReadyState.SAFE_MODE;
+    this.stateMessage = `Initialization failed due to error: ${errorToString(e)}`;
+    ...
+  }
+
   if (isMsgCheckForUpdates(msg)) {
     ...
   } else if (isMsgActivateUpdate(msg)) {
     ...
   }
 }

@gkalpak gkalpak reopened this Feb 18, 2019
@gkalpak
Copy link
Member

gkalpak commented Feb 18, 2019

@philipooo, since you see this error happening often (and you seem to be already instrumenting your code to gather insights), it would be great if you could track calls to driver.handleMessage() and driver.initialize() (including their start and end time) to see if this is indeed what is happening.

@philipooo
Copy link

Thank you. Of course I will. When loading the app the methods called like this:

  1. initialize() immediately
  2. handleMessage() after 1 minute and every minute, because of programmatical polling for updates

Payload of the handleMessage call

msg = {
    action: "CHECK_FOR_UPDATES",
    statusNonce: 9664259
}

from = {
    focused: false,
    frameType: "top-level",
    id: "f17313b0-b203-4d88-9d12-bd19303e53d9",
    type: "window",
    url: "https://...",
    visibilityState: "hidden"
}

@gkalpak
Copy link
Member

gkalpak commented Feb 19, 2019

Thx @philipooo. Have you verified whether the initialize() call is completed (it is an async function) before the call to handleMessage().
Basically, what we are interested is whether driver.sync() is called before driver.initialize() is completed (i.e. the promise returned by it is resolved).

Could you check that, @philipooo?

@benlesh benlesh added the area: service-worker Issues related to the @angular/service-worker package label Feb 20, 2019
@ngbot ngbot bot added this to the needsTriage milestone Feb 20, 2019
@philipooo
Copy link

philipooo commented Feb 25, 2019

Sorry for the delay. I am not sure whats the best sufficient way to debug the completion of the async calls. Can you give me some tips? (Chrome Dev Tools)

Update
It put breakpoints behind the yield this.initialized and yield this.sync() expressions to see when the lines get hit. Also I put breakpoints on the yield this.sync() expression itself.

What I see is:

  • First this line is hit

    this.state = DriverReadyState.SAFE_MODE;

  • About 5 seconds later this line

    (anonymous) (ngsw-worker.js:2527)
    fulfilled (ngsw-worker.js:1772)
    Promise.then (async)
    step (ngsw-worker.js:1774)
    fulfilled (ngsw-worker.js:1772)
    Promise.then (async)
    step (ngsw-worker.js:1774)
    (anonymous) (ngsw-worker.js:1775)
    (anonymous) (ngsw-worker.js:1771)
    cleanupCaches (ngsw-worker.js:2487)
    (anonymous) (ngsw-worker.js:2154) <-- this ist https://github.com/angular/angular/blob/f983e99fb245532b41125672447a7d6756e9da06/packages/service-worker/worker/src/driver.ts#L485
    fulfilled (ngsw-worker.js:1772)
    Promise.then (async)
    step (ngsw-worker.js:1774)
    (anonymous) (ngsw-worker.js:1775)
    (anonymous) (ngsw-worker.js:1771)
    (anonymous) (ngsw-worker.js:2151)
    (anonymous) (ngsw-worker.js:1714)
    fulfilled (ngsw-worker.js:1666)
    Promise.then (async)
    step (ngsw-worker.js:1668)
    (anonymous) (ngsw-worker.js:1669)
    (anonymous) (ngsw-worker.js:1665)
    (anonymous) (ngsw-worker.js:1711)
    (anonymous) (ngsw-worker.js:1711)
    (anonymous) (ngsw-worker.js:1669)
    (anonymous) (ngsw-worker.js:1665)
    execute (ngsw-worker.js:1706)
    (anonymous) (ngsw-worker.js:1702)
    fulfilled (ngsw-worker.js:1666)
    Promise.then (async)
    step (ngsw-worker.js:1668)
    (anonymous) (ngsw-worker.js:1669)
    (anonymous) (ngsw-worker.js:1665)
    trigger (ngsw-worker.js:1685)
    onFetch (ngsw-worker.js:1913)
    (anonymous) (ngsw-worker.js:1882)
    

I am not sure, but I think this means this.initialized completes before sync() is called the first time.

If you can give me some lines where I should place breakpoints I would be happy to do this.

@gkalpak
Copy link
Member

gkalpak commented Feb 25, 2019

Thx, @philipooo. I a little confused by your findings.

If this line is hit (as you mentioned), then the SW should be in DriverReadyState.SAFE_MODE mode and initialization has failed. But why did initialization fail? Was it because of this error?

Also, I am not sure if setting break points is a good way to debug this, since break points affect the timing of certain operations (so they can cover or cause race condition issues). I would be better if you could modify the SW script file to log when certain things happen (e.g. initialize() was called or completed, etc.). (TBH, I thought that is what you were doing 😁)

If you can do that and still reproduce the Invariant violated (initialize): latest hash null has no known manifest error (starting from a clean cache), then we can use that info to investigate further.

@philipooo
Copy link

Yes its because of the mentioned error. I tried to avoid modifing the SW script because I did not know if this would influence the reproducability of the error. But as there is no sufficient way debugging with breakpoints I will try to modifiy the script now. Stay tuned.

@philipooo
Copy link

philipooo commented Feb 25, 2019

I tried instrumenting sync initialize and handleMessage this way an hope this would not affect the behaviour of the SW script

Instrumentation example

sync() {
    console.log("sync() called");
    return __awaiter$5(this, void 0, void 0, function* () {
        // ...
    }).then(() => console.log("sync fulfilled"), () => console.log("sync rejected"));
}

Output

15:23:49.337 ngsw-worker.js:2128 initialize() called
15:23:49.356 ngsw-worker.js:2230 initialize rejected
15:23:49.486 ngsw-worker.js:1983 handleMessage() called
15:23:49.517 ngsw-worker.js:1992 handleMessage fulfilled
15:23:58.523 ngsw-worker.js:2466 sync() called
15:23:58.536 ngsw-worker.js:2487 sync fulfilled

@rebendajirijr
Copy link

rebendajirijr commented Apr 8, 2019

Just got the error in our app recently, is it somehow connected to opened dev tools? Is there any workaround?

Sounds like a major issue as it may prevent end users to run the app correctly.

@freefred81
Copy link

Hi everyone .. Same problem here:

Error:

ngsw-worker.js:2270 Uncaught (in promise) Error: Invariant violated (assignVersion): want AppVersion for null but not loaded
at Driver.lookupVersionByHash (ngsw-worker.js:2270)
at Driver. (ngsw-worker.js:2287)
at Generator.next ()
at ngsw-worker.js:1783
at new Promise ()
at ngsw-worker.js:1779
at Driver.assignVersion (ngsw-worker.js:2278)
at Driver. (ngsw-worker.js:2124)
at Generator.next ()
at fulfilled (ngsw-worker.js:1780)

the app throws error and crash chomre tab (all angular and chrome latest release)

The app is hosted on firebase with SSR (on firebase functions).

I've another app (same Angular version and on firebase and SSR on functions) and it work as aspected.

Any news?

THNX!!

@hsta
Copy link

hsta commented Jul 23, 2019

We have introduced the ngsw in our apps and are seeing a related or possibly even the same problem.

Here some additional information for our case (if it is a separate problem I guess/hope someone with deeper insight in the ngsw will be able to tell; I'll happily post a new report then).

Problematic Current Behavior

The service worker eventually ends up in SAFE_MODE on updates with the following ngsw/state:

(This is the message from #24333 since I messed up and forgot to copy+paste mine before I worked around it - I'll try to check if mine was actually identical when I get it the next time.)

Driver state: SAFE_MODE (Initialization failed due to error: Invariant violated (initialize): latest hash null has no known manifest
Error: Invariant violated (initialize): latest hash null has no known manifest
    at Driver.<anonymous> (https://DOMAIN/ngsw-worker.js:2170:27)
    at Generator.next (<anonymous>)
    at fulfilled (https://DOMAIN/ngsw-worker.js:1747:62))
Latest manifest hash: none
Last update check: XXXXXX



=== Idle Task Queue ===
Last update tick: XXXXXX
Last update run: XXXXXX
Task queue:


Debug log:

[XXXXXX] Error(Invariant violated (initialize): latest hash null has no known manifest, Error: Invariant violated (initialize): latest hash null has no known manifest
    at Driver.<anonymous> (https://DOMAIN/ngsw-worker.js:2170:27)
    at Generator.next (<anonymous>)
    at fulfilled (https://DOMAIN/ngsw-worker.js:1747:62)) Error occurred while updating to manifest HASH

This seems to happen only to some users on some updates, however eventually every test user with which we are in contact got this sooner or later.

Reproduction

Implement the ngsw with update and check for update implementations exactly like shown on https://angular.io/guide/service-worker-communications and perform a couple of updates with some test users. Eventually every user ended up in SAFE_MODE in our case.

Environment

Tested with @angular/pwa at 0.13.9, other Angular packages at 7.2.15 and Chrome/75.0.3770.102 but probably similar in other versions.

Notable things

The information provided by @philipooo was exactly the same in our case. Additionally I can say that in the problematic cases the control table actually had the three entries but they actually only contained entries exactly like the output @philipooo provided at 3.

Possibly related issues

#24333, #22087, https://stackoverflow.com/questions/54455518/angular-service-worker-is-in-safe-mode

Workarounds

  • Manual/Temporary workaround: Simply unregistering the service worker and clearing the app cache. Afterwards the service worker will work as expected in NORMAL state but obviously it may break in future on future updates again.
  • Permanent/Hacky workaround:
    In the ngsw-worker.js find
                try {
                    // Read them from the DB simultaneously.
                    [manifests, assignments, latest] = yield Promise.all([
                        table.read('manifests'),
                        table.read('assignments'),
                        table.read('latest'),
                    ]);

And add the following line after the found code:

if (latest.latest === null) throw new Error('Error latest.latest is null for what ever reason...')

Since the catch block seems to have a reasonable fallback logic, by throwing at that point in that case SAFE_MODE is prevented and at least in first tests the service worker keeps to work as expected. However, I could imagine some things still don't work as expected. For example I had the feeling the Clients: in ngsw/state grew a bit too fast - maybe someone with ngsw insights could comment on this workaround?
Also obviously hacking in ngsw-worker.js is ugly (we do it with sed in our build pipeline) and another workaround would be desirable...

@davidpadych
Copy link

Was it possible to make a patch for version 7.x.x? thx

@gkalpak
Copy link
Member

gkalpak commented Nov 6, 2019

I'm afraid not. 7.x is in LTS mode, which means only critical fixes and security patches are released.

@davidpadych
Copy link

I understand.. and 8.2.x ?

mohaxspb pushed a commit to mohaxspb/angular that referenced this issue Nov 7, 2019
…ngular#32525)

- resolves "Invariant violated (initialize): latest hash null has no known manifest"
- Thanks to @gkalpak and @hsta for helping test and investigate this fix

Fixes angular#25611

PR Close angular#32525
mohaxspb pushed a commit to mohaxspb/angular that referenced this issue Nov 7, 2019
…ngular#32525)

- resolves "Invariant violated (initialize): latest hash null has no known manifest"
- Thanks to @gkalpak and @hsta for helping test and investigate this fix

Fixes angular#25611

PR Close angular#32525
gkalpak pushed a commit to gkalpak/angular that referenced this issue Nov 11, 2019
…ngular#32525)

- resolves "Invariant violated (initialize): latest hash null has no known manifest"
- Thanks to @gkalpak and @hsta for helping test and investigate this fix

Fixes angular#25611

PR Close angular#32525
@gkalpak
Copy link
Member

gkalpak commented Nov 11, 2019

Sorry for taking so long to get back.
Yes, it should be backported to 8.2.x. I created #33744. (It should hopefully be released this week.)

kara pushed a commit that referenced this issue Nov 11, 2019
…32525)

- resolves "Invariant violated (initialize): latest hash null has no known manifest"
- Thanks to @gkalpak and @hsta for helping test and investigate this fix

Fixes #25611

PR Close #32525
@davidpadych
Copy link

davidpadych commented Nov 11, 2019

for those who use angular 7.x...

  1. copy ngsw-worker.js from node_modules/@angular/service-worker/ngsw-worker.js to root of project
  2. add fix from comment gkalpak
  3. add "copy:worker": "cp ngsw-worker.js dist/" to package.json
  4. edit build script... "build": "... && npm run copy:worker"

@gkalpak
Copy link
Member

gkalpak commented Nov 13, 2019

Big WARNING:
Using mismatching versions of @angular/* packages is not guaranteed to work 😁

@paustint
Copy link

@gkalpak - I know this ticket is closed, but I was not sure where else to post this.

With the patch applied, I have still gotten the error on at least one machine (code not yet released to users) Error: Invariant violated (initialize): latest hash null has no known manifest.

The good news is that the browser is still served the new version of the application instead of the old one if there is an update (which is a very huge improvement).

I have looked through all the Angular SW APIs and it appears that there is no way for me to programmatically know that there is a failure and it appears there is no way to programatically recover from this.

Do you have any advice on how I might detect the error and recover from this programmatically on a user-by-user basis?

NGSW Debug Info:

Driver state: SAFE_MODE (Initialization failed due to error: Invariant violated (initialize): latest hash null has no known manifest
Error: Invariant violated (initialize): latest hash null has no known manifest
    at Driver.<anonymous> (https://foo.com/ngsw-worker.js:2255:27)
    at Generator.next (<anonymous>)
    at fulfilled (https://foo.com/ngsw-worker.js:1787:62))
Latest manifest hash: none
Last update check: 8m22s81u



=== Idle Task Queue ===
Last update tick: 3s891u
Last update run: 8m22s180u
Task queue:


Debug log:

[8m31s751u] Unknown version null mapped for client f7a16ae2-27d0-4dd2-b9cd-4d807d3ef067, using latest instead initialize: map assignments
[8m21s948u] Error(Invariant violated (initialize): latest hash null has no known manifest, Error: Invariant violated (initialize): latest hash null has no known manifest
    at Driver.<anonymous> (https://foo.com/ngsw-worker.js:2255:27)
    at Generator.next (<anonymous>)
    at fulfilled (https://foo.com/ngsw-worker.js:1787:62)) Error occurred while updating to manifest 7d01e1bc3876fa88dc435c0dcd31184103d8be34

@gkalpak
Copy link
Member

gkalpak commented Nov 27, 2019

@paustint, do you have a way to know whether the machine you saw this on had already updated to the new SW. Because, even if your app has been updated with the fix, I think it is still possible for the old SW to be activated and run into the issue before being replaced by the new one.

Regarding recovering from this, the SW should be able to recover automatically (e.g. the next time it is instantiated, after clients have been closed).

Can you check in the cache (e.g. in DevTools > Application > Cache Storage) and see what is the stored value for /latest in the cache named ngsw:/:db:control?

@paustint
Copy link

paustint commented Nov 27, 2019

@gkalpak - I actually never merged any service worker code into my core codebase until just now, so while this computer did have the old service worker 4 months ago, it has accessed the application where no ngsw file was present. (I might have even manually un-registered the old SW)

I am pretty confident this is the new service worker.

The old service worker would have been dated sometime in early august and we have not used it in-between until now.

I have released multiple new versions of the application, but this client fails every time. It DOES use the latest version of the code and not a cached version.

image

@paustint
Copy link

@gkalpak - Looking at the code in the error, I do see the code that was added with the patch and did not previously exist.

image

@gkalpak
Copy link
Member

gkalpak commented Nov 28, 2019

Hm...it could also be the case that this breaks because null is already saved in the cache. (The fix is about avoiding saving null as /latest, but maybe we are not recovering correctly if null is already saved in the cache (e.g. by an older, buggy SW version).)

What happens if you clear the cache? Can you still reproduce the error?
(I tried to reproduce this on https://next.angular.io/ (by putting null in the cache), but the SW seems to recover fine 🤷‍♂)

@gkalpak
Copy link
Member

gkalpak commented Nov 28, 2019

BTW, I assume this failing machine is not publicly accessible, right?

@paustint
Copy link

@gkalpak

BTW, I assume this failing machine is not publicly accessible, right?

The machine with the issue is a laptop and is not public facing.

What happens if you clear the cache? Can you still reproduce the error?

I cleared the cache (clicked each entry and right click > delete) and I still have the same problem where the SW is in an invalid state and no new cache entries were added and I got the same error message if I tried to run an update (via the updates service).

Eventually I clicked the "update on reload" checkbox in chrome devtools and after a page refresh the service worker did recover and is now working on this machine.

I will keep an eye on it through staging and production to see if the error pops up again, but I am really hopeful that the error will not occur again.

@gkalpak
Copy link
Member

gkalpak commented Dec 1, 2019

Thx for the update, @paustint 👍
Let's see if it happens again.

@LuisReinoso
Copy link
Contributor

We had the same issue too and it is persistent when user has old version of app with cache issue then /latest has null even after update angular service worker. By this reason we are cleaning cache /latest from ngsw:/:db:control on this.updates.available. from SwUpdate. To prevent error from old users.

window.caches.open('ngsw:/:db:control').then(cache => cache.delete('/latest').then(remove => console.info('cache storage ngsw /latest removed')))

@gkalpak
Copy link
Member

gkalpak commented Dec 4, 2019

Weird that I couldn't reproduce it on https://next.angular.io/, but 🤷‍♂
Is anyone interested in submitting a PR to make the SW more robust against this bad state, please do ✨

(Also, I would be very interested to know if the error happens again once updated to the latest SW, so let me know here 🙏)

@prp1
Copy link

prp1 commented Dec 18, 2019

After updating:

  • @angular/pwa from 0.13.6 to 0.803.20
  • @angular/service-worker from 8.0.1 to 8.2.14
  • also other angular packages to 8.2.14

When app is deployed and a new version is available, I started to get service worker errors. In console I get such error:

Service worker event waitUntil() was passed a promise that rejected with 'Error: Invariant violated (initialize): latest hash null has no known manifest'.

However, ngsw/state shows this:

NGSW Debug Info:

Driver state: NORMAL ((nominal))
Latest manifest hash: none
Last update check: never

=== Idle Task Queue ===
Last update tick: never
Last update run: never
Task queue:

Debug log:

In code I subscribe to swUpdate.available event and check for updates manually (on every successful login to the app). In Chrome event is fired, in Firefox - sometimes yes, sometimes not.

However, all above is true for chrome in incognito mode, or for Chrome on my colleagues laptops, that are not developing Angular, using devtools etc. On my Chrome instance, not incognito mode, ngsw/state always shows this:

NGSW Debug Info:

Driver state: SAFE_MODE (Initialization failed due to error: Invariant violated (initialize): latest hash null has no known manifest
Error: Invariant violated (initialize): latest hash null has no known manifest
    at Driver.<anonymous> (https://foo/ngsw-worker.js:2272:27)
    at Generator.next (<anonymous>)
    at fulfilled (https://foo/ngsw-worker.js:1801:62))
Latest manifest hash: none
Last update check: never


=== Idle Task Queue ===
Last update tick: 930u
Last update run: 58m25s941u
Task queue:


Debug log:

[58m25s938u] TypeError(Failed to fetch, TypeError: Failed to fetch) Driver.fetch(https://foo/ngsw.json?ngsw-cache-bust=0.7630465402297053)
[58m25s938u] Check for update aborted. (Client or server offline.) 

What I am afraid of is that service worker does not work not only for me, but may not work stable enough for end users too.

I would be happy to provide more info or event sequence how all of this happens, if that would help to fix these problems.

@gkalpak
Copy link
Member

gkalpak commented Dec 18, 2019

@prp1, it is not exactly clear to me what fails and when. Are you saying this happens even after you clear the cache and SW (e.g. Chrome DevTools > Application > Clear storage > Clear site data)?

If so, could you try to debug this and get an (async) stack trace of the rejection (i.e. what function calls lead to the rejected promise)?

@prp1
Copy link

prp1 commented Dec 18, 2019

I haven't cleared the cache and SW (e.g. Chrome DevTools > Application > Clear storage > Clear site data). After doing this, everything again works as expected.

Is it known what could have caused the need to clear the cache and SW? Is it possible that simple users will need to do the same? If yes, is it known how to fix the issue programmatically?

@gkalpak
Copy link
Member

gkalpak commented Dec 18, 2019

I haven't been able to reproduce this, but some people have reported that if the cache was in a bad state (from a previous SW version) than the latest SW would fail to recover. If someone can provide a reproduction of this, I would be happy to investigate the root cause.

In the meantime, PRs making the SW more robust to a bad cache are welcome (see #25611 (comment)).

I can't really say how this can be fixed programmatically (because it is not clear to me what is causing the problem), but if it is related to the caches you can delete them by doing something similar to the SW's deleteAllCaches() method. It would look something like this:

caches.keys().
  then(cacheNames => cacheNames.filter(name => name.startsWith(`ngsw:`))).
  then(cacheNames => Promise.all(cacheNames.map(name => caches.delete(name))));

Both the page and the SW share the same CacheStorage object, so you can run the above code on the page (not necessarily in the SW).

@paustint

This comment has been minimized.

@philipooo

This comment has been minimized.

@paustint

This comment has been minimized.

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Jan 19, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: service-worker Issues related to the @angular/service-worker package freq2: medium type: bug/fix
Projects
None yet
Development

Successfully merging a pull request may close this issue.