Subscribe on changes!

`router.push()` during setup leads to "Unhandled error during execution of scheduler flush." and then `node is null`

avatar
May 30th 2022

Vue version

3.2.36

Link to minimal reproduction

https://codesandbox.io/s/vue-router-push-setup-node-is-null-gwfl0f

Steps to reproduce

As soon as you open the reproduction you should be able to see the issue: image

What is expected?

I would expect the redirect to happen without any issue.

What is actually happening?

There is currently an issue:

node is null

That is emitted after the following warning:

Unhandled error during execution of scheduler flush. This is likely a Vue internals bug.

System Info

No response

Any additional comments?

Context on discovery

I ran into this bug after implementing a "login by token", once the user would log in the app it would be redirected to the page he was requesting. Doing this like the above leads to the issue. In order to avoid an async setup I changed my code to something like:

<script setup>
import { useRouter } from "vue-router";

const router = useRouter();
- await router.push({ path: "/about" });
+ Promise.resolve().then(() => { router.push({ path: "/about" }); });
</script>

What seems to happen

It looks like:

  1. VueJs is waiting to render the component
  2. The router redirect to another route
  3. VueJs renders the new route
  4. VueJs tries to compute the diff with the old view state, here it fails as this view has never been rendered

Correct approach

I am unsure that my approach is the correct one, in fact I declare a view that will never be rendered, there may be other approach that are more correct in this context.

avatar
May 31st 2022

maybe you should use isReady instead.

router.isReady().then(onSuccess).catch(onError)

see https://router.vuejs.org/guide/migration/#replaced-onready-with-isready

avatar
Jun 1st 2022

I did not knew about the isReady method. I did not try with this, instead I went to use a beforeEnter navigation guard with an empty component:

const routes = [
  {
    path: '/login/:token',
    name: 'login-token',
    beforeEnter: async (_to, _from, next) => {
      await Promise.resolve(true); // Here I am doing calls to my API.
      next({ path: '/about' });
    },
    component: () => '',
  },
];