vue-router: $router.push() followed by redirect in a route's beforeEnter hook causes uncaught promise rejection
Version
3.1.3
Reproduction link
https://jsfiddle.net/asu3qnry/
Steps to reproduce
To trigger the uncaught promise rejection, click on “/home” and then the button.
What is expected?
No uncaught promise rejection because there are actually no errors generated by the application. It’s simply a navigation ($router.push) that generates a redirect (next('/foo')) in a beforeEnter hook.
What is actually happening?
Console reports: Uncaught (in promise) undefined
Using a router-link to /bar instead of the initial $router.push('/bar') does not produce the error.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 23
- Comments: 18 (3 by maintainers)
Commits related to this issue
- Implemented `home` button navigation Also fixed uncaught exceptions when redirecting with `router.push`, see https://github.com/vuejs/vue-router/issues/2932 — committed to alex-c/OpenMTS by alex-c 4 years ago
- menyelesaikan undefined error vue-router (https://github.com/vuejs/vue-router/issues/2932) — committed to duro06/m.capcin.vue by duro06 4 years ago
- fix(bridge): correct `unhandled promise rejection: undefined` fact: This error is occurred by aborting a pending navigation. Reason: The first router initialization might override first bridge calli... — committed to lbwa/qwebchannel-bridge by lbwa 4 years ago
@posva Thanks for the clarification! However, I would argue that a redirection that cancels a navigation should not be a Promise rejection. Since rejection becomes a throw in the async/await model, it should only occur on actual errors. In my opinion, an expected control flow with a redirection should not have to add error handlers to avoid errors. While reading #2881 and the relevant documentation again, I could not find a description of what
$router.push()actually resolves to; only that it should resolve (or reject) when navigation is complete.The example code you gave in #2881 inspired me to create this global
push()override:Since the precise resolve/reject behavior of
push()doesn’t seem set in stone, would it be possible to resolve to the final route (orfalseif navigation aborted) instead of rejecting when there is no error?I already answered this at https://github.com/vuejs/vue-router/issues/2833#issuecomment-532158403
Please, check the related issues, the reasoning has been verbosely explained there already
@posva I did read your previous reply and the referenced issue #2881 in its entirety. Here’s why I thought this issue is different in more detail:
NavigationDuplicatedis mentioned all over the place in #2881 but it is not involved at all in my jsfiddle. For reference, here is the stack trace from my jsfiddle in Chrome:And the code at
abort @ vue-router.js:2088:My understanding is that the whole discussion in #2881 is centered around error handling. My use-case does not involve any error-generating code path. Here is where the
abort()is triggered inconfirmTransition():I understood your comment in #2833 (comment) as telling me that my issue was separate from #2833.
I spent quite some time debugging, researching and reproducing this in a minimal test case and I honestly thought this issue was different from the others linked. Note also that, in an attempt to not add noise to the repo, my first step was to find another related issue and not hastily create a new one 😃. Of course all these issues are related to
Promiserejection so maybe they will all be fixed the same way.Why is this issue still closed? The “supposedly” related issues where closed but this is still valid (which show they weren’t the same) The proposed solution of @berniegp works, so please reopen the issue and review the proposal to either allow a PR or reject it with at least some feedback.
This error is really annoying 👎 this is the first time I see something like this, and it ends having all kind of reverse situations if you want to check auth before the call 😦
If got this Error in my console:
Uncaught (in promise) TypeError: Cannot read property 'toString' of undefinedAfter a while of debugging, this is due to the abort call described above with undefined as error.
Maybe a better solution is throwing a real error like NavigationCanceled or something.
Calling router push with empty function fixed it magically:
$router.push('/', () => {})Have the same problem. I have another question I have big project and now I should implement this $router.push(‘/’, () => {}) everywhere why? @berniegp good solution but why it is not in core package?
Any navigation failure is a promise rejection. I updated my comment at https://github.com/vuejs/vue-router/issues/2881#issuecomment-520554378 that explains everything. Let me know if there is anything to add
Some errors haven’t been changed yet and that’s why the uncaught error may be
undefinedorfalsein some scenarios