Subscribe on changes!

Suspense+KeepAlive+AsyncComponent+v-if causes the `Uncaught (in promise): Cannot read properties of null (reading 'parentNode')`

avatar
Aug 13th 2022

Vue version

3.2.37

Link to minimal reproduction

https://play.vuejs.org/#eNqNVMtu2zAQ/JWFLpGBWEyRnlLZiBvk0BZtg9pHXRRpZTGVSIKk/EDgf++SlGzVToCcLHJfM7NDv0YLpZJNh9FdlFpsVZNbnGcCIF12RqEw4UTnkm/6Tzr8QFSLhm+GqL98aNXC7EUBmymvZlnEzbKWW5FFwE6V7Lw0ZUPnlI1mpmwEJzWF5sqCQdspn8tbJbWF19CjxIoL9MMfJEUECnsdQlL8lJ2wWPZnjZX/OkClZQtXxP3qy6gjkegjCXO9nDguwaUUUhifEWjO3pwbhznxBGZzELiFJ+rGDcaxRuMve9Dg6Kx4i7KzcUinjJjaT67h083NzcTjIqgT9+tOJxC9toSBCMVWdzjEj4T7nv20i1lHFIwBr1z82NRKcB3B1igAN6j3tuZiDVveNPCM4EiPqqWGzqDf/xw4ocO8BFmdDHHcfj8g2eQNtZ9BlTcGB5aedOB8cD8pC1ufR9dRWM60zVXyYqQgt3r45DEfMFl0NxDKItqYO2dRba0yd4wVpaCyEsl1OhFomVAtu6c0pkkpUmVayvb+NrlNPpMZjR1fJ2ja6bOWW4OammRR7yM/htElyTPVKErUqD869qxsPPosdDHey5OJA4ky2PPy7Z7e6qrmBizu6O3UsmtKciS1d0ukaVSxxzI8vVAyenU0wBoyW8XXZ5oXNJc3qH8ry8mM/2mfN43cfvd3zkJHsYoai79v3L+YXRDtibzvqI8Etrleow3hx+UvIjEKtrLsmn7P7wT/oJFN5zCGtK+dKAn2KM+j/eYtRP5emcedpb+fgZQD6uX2+X7hTvL3qJ/g0jqPazr8AxfWwHU=

Steps to reproduce

The reproduction link demonstrates the issue with no action required.

  1. Put an async component inside the <KeepAlive>.
  2. Assume we have <Suspense> somewhere up in the tree.
  3. Add conditional rendering to that async component using v-if. The initial condition should be set to true.
  4. Change that condition to the false before the async component is fully loaded.

What is expected?

The async component is loaded but not rendered. No errors in the logs.

What is actually happening?

[Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug. Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/core 
  at <KeepAlive> 
  at <Repl>

vue.runtime.esm-browser.js:9243 Uncaught (in promise) TypeError: Cannot read properties of null (reading 'parentNode')
    at parentNode (vue.runtime.esm-browser.js:9243:30)
    at ReactiveEffect.componentUpdateFn [as fn] (vue.runtime.esm-browser.js:7062:17)
    at ReactiveEffect.run (vue.runtime.esm-browser.js:531:25)
    at instance.update (vue.runtime.esm-browser.js:7094:56)
    at updateComponent (vue.runtime.esm-browser.js:6919:26)
    at processComponent (vue.runtime.esm-browser.js:6852:13)
    at patch (vue.runtime.esm-browser.js:6450:21)
    at patchBlockChildren (vue.runtime.esm-browser.js:6756:13)
    at patchElement (vue.runtime.esm-browser.js:6664:13)
    at processElement (vue.runtime.esm-browser.js:6530:13)

Notes

Another issue here is Uncaught (in promise): suspense.resolve() is called without a pending branch. error that is thrown if there is no KeepAlive component in the tree. This error is caused by double calling the "resolve" method of the same suspense object when an async component is unmounted before the resolution of the suspense.

https://github.com/vuejs/core/blob/3be4e3cbe34b394096210897c1be8deeb6d748d8/packages/runtime-core/src/renderer.ts#L2274-L2290

https://github.com/vuejs/core/blob/3be4e3cbe34b394096210897c1be8deeb6d748d8/packages/runtime-core/src/components/Suspense.ts#L224-L226

You can put an async component into a wrapper component (it can just render the default slot). In that case neither KeepAlive or Suspense is rerendered. Although this makes KeepAlive useless.

https://play.vuejs.org/#eNqNVE1P4zAQ/Suj7GFTicZ0uye2rWARh/1GC8dcQjIhhsS2bKcFof73HdtJmhSQ9pSM5/O9efZLdKFUsm0xOotWFhtVZxY3qQBY3bRGoTDBIrvg2+6XjB+I6qLm297rDy8btRjZ4eTCPIsctnNertOIm5tK7kQaARsnsknmih1XX7FD82FK+FBmdX2X5Y9D5k+ZFVzcJ0nS500hsRGmiW9lcs2VBYO2VT6WN0pqCy+hUIElF+ihXEryCBT2JLik+CVbYbHobI2l/9tDqWUDH4nbj19GFQlq50mYq+XIPw5YTCIWfYgLyqUwPibwun5ztDiMEs9gvQGBO7imctxgHGs0/rDDBQ7xLW9QtjYO4RQRU/nZCSxOT09nfjJCM3NfZx2G6JZJMxDm2OoWe//ASVez6/aq1zAFY8BL5x+KWgmuItgKBeAW9bOtaLWw43UNdwgO9ChbamgNesFtgNN0mBUgy4MCB410DZJtVlP5NZCIDPYoPeiAee8+KxaEsYlOorCeeZOp5MFIQRfGj0+i9g6TRmc9oDSijTk7jSprlTljLC8EpRVIqtaJQMuEatg5hTFNTBEr80I258vkU7L8TGo3dnyeoGnmd1ruDGqqkkad1nwfRofEz1yjKFCj/t++R2mT3ke+V/09QanYEy29hl8/IIc7e1txAxaf6IJVsq0L0iSVd2ukbpTxjEW4nyFldDWpgTUkt5LfH7GeU19eo/6jLCc5Ttind0HuvvszJ6KBrbzC/PGN8wfzFFi7JvU76COGbabv0Qb31c1vAjFyNrJo627T7zj/opF162YMYV9bUdDYozg/7TcvIlL4rbl6svRG9aDcoJ5uH+837ih/D/ph3GWyPFqTf0ime9Ked1NL615kssbc7/8Bq7z4Vg==

avatar
Sep 23rd 2022

Same error, what's the progress?

avatar
Oct 3rd 2022

在vuepress 2.x下面有同样的问题 image

avatar
Feb 17th 2023

The reproduction throws the same error on vue v3.2.36

avatar
Feb 17th 2023

I had the same issue inside a Nuxt v3.2.2 app, probably caused by a suspense boundary with async components.

In the following line prevTree.el is null, when the error is thrown (null.parentNode). Sometimes it is "", which does not throw, as "".parentNode gives undefined, which does not cause any problems. https://github.com/vuejs/core/blob/a0e7dc334356e9e6ffaa547d29e55b34b9b8a04d/packages/runtime-core/src/renderer.ts#L1496

I think it is some kind of race condition, where the prevTree.el is not available, because of the async component being removed / not being ready.

avatar
Feb 23rd 2023

Same issue for me with Nuxt 3.1.1.

Changing line 35 of @vue/runtime-dom runtime-dom.esm-bundler.js to parentNode: node => node ? node.parentNode : null, seems to fix the issue though I am not sure what downstream effects this could have.

avatar
Apr 5th 2023

Same issue here.

avatar
May 2nd 2023

Same issue on my side :(

avatar
Jul 3rd 2023

Here is another reproduction that does not seemingly make use of KeepAlive but still triggers this error. https://stackblitz.com/edit/github-8d62xc To trigger, click on one of the links.

The code is nonsensical from the practical aspect as it hides the element when it loads the fallback component. Despite this, it is hard for me to assess whether the code itself is valid and belongs to the same type of issue.

avatar
Sep 22nd 2023

I have same issue, so only this answer helped me. Hope it will be fixed soon

Same issue for me with Nuxt 3.1.1.

Changing line 35 of @vue/runtime-dom runtime-dom.esm-bundler.js to parentNode: node => node ? node.parentNode : null, seems to fix the issue though I am not sure what downstream effects this could have.

avatar
Oct 20th 2023

Same issue for me with Nuxt 3.1.1.

Changing line 35 of @vue/runtime-dom runtime-dom.esm-bundler.js to parentNode: node => node ? node.parentNode : null, seems to fix the issue though I am not sure what downstream effects this could have.

Had the same problem in nuxt 3.8.0. Finally solved by patching in this way! Thank you, i hope can be helpful for the fix

avatar
Oct 27th 2023

this is serious issue - is it on the roadmap?

avatar
Oct 29th 2023

The problem is here: https://github.com/vuejs/core/blob/3be4e3cbe34b394096210897c1be8deeb6d748d8/packages/runtime-core/src/components/Suspense.ts#L211-L244 When the component is toggled before the pending tree is resolved, patching should not be performed. Instead, the logic under the "else" statement should be executed. based on the current code, the component should be used as the root node of Suspense and should not be wrapped by any other elements.

The correct nesting order should be as follows:

<KeepAlive>
  <Suspense>
    <!-- main content -->
    <component :is="Component"></component>

    <!-- loading state -->
    <template #fallback>
      Loading...
    </template>
  </Suspense>
</KeepAlive>

see https://vuejs.org/guide/built-ins/suspense.html#combining-with-other-components

or add a key see

<Suspense>
  <div :key="+isShown">
    <KeepAlive>
      <CmpAsync v-if="isShown" />
    </KeepAlive>
  </div>
</Suspense>

this will be fixed via #7290