vuejs/router

Empty error message in production environment when using ESM build

kleinfreund opened this issue · 4 comments

Reproduction

https://github.com/kleinfreund/vue-router-empty-error-reproduction

Steps to reproduce the bug

Steps to reproduce

  1. Start the development environment by running vite (e.g. npx vite, yarn vite).

  2. Go to http://localhost:5173/ and take note of the console warning and error.

    [Vue warn]: Unhandled error during execution of setup function
      at <RouterLink to= {name: 'non-existing-route'} >
      at <App>
    
    vue-router.js?v=271f20ea:750 Uncaught Error: No match for
     {"name":"non-existing-route","params":{}}
        at createRouterError (vue-router.js?v=271f20ea:750:19)
        at Object.resolve (vue-router.js?v=271f20ea:1202:15)
        at Object.resolve (vue-router.js?v=271f20ea:2320:34)
        at vue-router.js?v=271f20ea:1597:39
        at ReactiveEffect.fn (chunk-3CCIBI4V.js?v=271f20ea:1237:13)
        at ReactiveEffect.run (chunk-3CCIBI4V.js?v=271f20ea:430:19)
        at get value (chunk-3CCIBI4V.js?v=271f20ea:1249:107)
        at useLink (vue-router.js?v=271f20ea:1633:22)
        at setup (vue-router.js?v=271f20ea:1674:27)
        at callWithErrorHandling (chunk-3CCIBI4V.js?v=271f20ea:1657:19)
    
  3. Build for production by running vite build (e.g. npx vite build, yarn vite build).

  4. Run http-server dist (e.g. npx http-server dist, yarn http-server dist).

  5. Go to http://localhost:8080/ and take note of the console error.

    index-w07yFLF8.js:13 Error
        at yt (index-w07yFLF8.js:21:6095)
        at Object.d [as resolve] (index-w07yFLF8.js:21:10933)
        at Object.T [as resolve] (index-w07yFLF8.js:21:18123)
        at index-w07yFLF8.js:21:14301
        at Zn.fn (index-w07yFLF8.js:9:8939)
        at Zn.run (index-w07yFLF8.js:9:1446)
        at get value (index-w07yFLF8.js:9:9183)
        at index-w07yFLF8.js:21:14349
        at Zn.fn (index-w07yFLF8.js:9:8939)
        at Zn.run (index-w07yFLF8.js:9:1446)
    

Expected behavior

The error in the production build tells me something about the nature of the route resolution error.

Actual behavior

The error in the production build only has an intact stack trace, but no error message and, importantly, no information about which route couldn’t be resolved including the used parameters is provided.

Additional information

In error monitoring, every now and then, I notice errors that are reported with only a stack trace and no error message whatsoever. The only clue was that, with sourcemaps, the stack trace was related to the following lines of code in vue-router’s ESM build:

    else {
        return assign(new Error(), {
            type,
            [NavigationFailureSymbol]: true,
        }, params);
    }

Corresponding source code:

} else {
return assign(
new Error(),
{
type,
[NavigationFailureSymbol]: true,
} as { type: typeof type },
params
) as E
}

This makes it unnecessarily hard to figure out what’s wrong as all I have to go by when looking at Datadog logs (for example) is a "Error: Empty message" entry and the URL at which it occurred. With a sufficiently complex application, that makes it quite tedious to identify which route resolution is going wrong.

The error still contains all the information. Just not the text message, just its code (type)
Vue core has a similar feature.
The text they print when logged is a different story but the platform you use should be able to give you access to the error object. Other than that, anything missing in the error?

The Error object that is being logged does indeed hold the relevant information. I can confirm this by adding a custom error handler and logging the object itself:

app.config.errorHandler = function (err, vm, info) {
  console.log(err) // has `.location`
}

However, without custom error handling exposing this (we don’t customize errorHandler in our application), that information is invisible when looking directly at the browser console.

Whether Datadog or other tools at least in theory have the ability to look at the Error object itself, I don’t know. At least in our setup, any further information beyond the stack trace seems lost.

I see. Then things are working correctly. If you want the error to be logged in a particular way, that’s application code you should add to fit your needs

As a workaround, I’m considering to apply the following custom error handler in our application:

app.config.errorHandler = function (error) {
  // Patches the vue-router MATCHER_NOT_FOUND error message back into the error object because vue-router explicitly creates an `Error` object with no message in production environments.
  if (
    import.meta.env.PROD &&
    error instanceof Error &&
    error.message === '' &&
    'type' in error &&
    error.type === 1 &&
    'location' in error
  ) {
    // Changing `error.message` causes Vue to throw the error twice even when `errorHandler` throws the same `Error` object.
    error.message = `No match for ${JSON.stringify(error.location)}${router.currentRoute.value
      ? ` while being at ${JSON.stringify(router.currentRoute.value.fullPath)}`
      : ''}`

    throw error
  }

  throw error
}