Suspense+KeepAlive+AsyncComponent+v-if causes the `Uncaught (in promise): Cannot read properties of null (reading 'parentNode')`
Vue version
3.2.37
Link to minimal reproduction
Steps to reproduce
The reproduction link demonstrates the issue with no action required.
- Put an async component inside the
<KeepAlive>
. - Assume we have
<Suspense>
somewhere up in the tree. - Add conditional rendering to that async component using
v-if
. The initial condition should be set totrue
. - 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.
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.
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.
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.
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.
On 3.3, this can be resolved by using a nested
<Suspense suspensible>
:
Is this implemented in Nuxt? Maybe @danielroe might be interested for https://github.com/nuxt/nuxt/issues/13309
Nuxt 3.7.3
Detailed reproduction: https://stackblitz.com/edit/nuxt-starter-btlcfb?file=pages%2Fwaiting.vue
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
toparentNode: node => node ? node.parentNode : null,
seems to fix the issue though I am not sure what downstream effects this could have.
Same issue for me with Nuxt 3.1.1.
Changing line 35 of @vue/runtime-dom
runtime-dom.esm-bundler.js
toparentNode: 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
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
duplicate of https://github.com/vuejs/core/pull/6095