Skip to content

Custom errors get formatted as JSON objects in the console #7745

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
6 tasks done
dmaretskyi opened this issue Mar 27, 2025 · 3 comments
Open
6 tasks done

Custom errors get formatted as JSON objects in the console #7745

dmaretskyi opened this issue Mar 27, 2025 · 3 comments

Comments

@dmaretskyi
Copy link

Describe the bug

Custom errors that have toJSON method, get formatted as JSON-objects in the console.

We're overriding toJSON to serialize errors that a passed across API-boundaries. The JSON blob emitted isn't easy to read.

Is there a way to implement a custom error serializer for vitest?

Console output:

 RERUN  test/basic.test.ts x4 

 ❯ test/basic.test.ts (1 test | 1 failed) 1ms
   × throw error 1ms
     → undefined

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯

 FAIL  test/basic.test.ts > throw error
{
  tag: 'MY_ERROR',
  stackStr: 'Error: error message\n' +
    '    at throwError (/home/projects/vitest-dev-vitest-659jeds3/test/basic.test.ts:25:11)\n' +
    '    at eval (/home/projects/vitest-dev-vitest-659jeds3/test/basic.test.ts:28:3)\n' +
    '    at eval (file:///home/projects/vitest-dev-vitest-659jeds3/node_modules/@vitest/runner/dist/index.js:217:14)\n' +
    '    at eval (file:///home/projects/vitest-dev-vitest-659jeds3/node_modules/@vitest/runner/dist/index.js:608:28)\n' +
    '    at eval (file:///home/projects/vitest-dev-vitest-659jeds3/node_modules/@vitest/runner/dist/index.js:99:24)\n' +
    '    at https://vitestdevvitest659jeds3-lueh.w-credentialless-staticblitz.com/blitz.33edf5bb.js:40:25129\n' +
    '    at new Promise (<anonymous>)\n' +
    '    at new Promise (https://vitestdevvitest659jeds3-lueh.w-credentialless-staticblitz.com/blitz.33edf5bb.js:40:25088)\n' +
    '    at runWithTimeout (file:///home/projects/vitest-dev-vitest-659jeds3/node_modules/@vitest/runner/dist/index.js:76:12)\n' +
    '    at runTest (file:///home/projects/vitest-dev-vitest-659jeds3/node_modules/@vitest/runner/dist/index.js:1237:17)',
  nameStr: 'Error',
  expected: 'undefined',
  actual: 'undefined',
  stacks: [
    {
      method: 'throwError',
      file: '/home/projects/vitest-dev-vitest-659jeds3/test/basic.test.ts',
      line: 25,
      column: 11
    },
    {
      method: 'eval',
      file: '/home/projects/vitest-dev-vitest-659jeds3/test/basic.test.ts',
      line: 28,
      column: 3
    },
    { method: '', file: '/blitz.33edf5bb.js', line: 40, column: 25129 },
    {
      method: 'new Promise',
      file: '/blitz.33edf5bb.js',
      line: 40,
      column: 25088
    }
  ]
}
 ❯ throwError test/basic.test.ts:25:11
     23| test('throw error', () => {
     24|   function throwError() {
     25|     throw new MyError('error message');
       |           ^
     26|   }
     27| 
 ❯ eval test/basic.test.ts:28:3
 ❯ ../../../blitz.33edf5bb.js:40:25129
 ❯ new Promise ../../../blitz.33edf5bb.js:40:25088

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯


 Test Files  1 failed (1)
      Tests  1 failed (1)
   Start at  12:01:32
   Duration  20ms

 FAIL  Tests failed. Watching for file changes...
       press h to show help, press q to quit

Reproduction

https://stackblitz.com/edit/vitest-dev-vitest-659jeds3?file=test%2Fbasic.test.ts,package.json,tsconfig.json&initialPath=__vitest__/

System Info

System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 18.20.3 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 10.2.3 - /usr/local/bin/npm
    pnpm: 8.15.6 - /usr/local/bin/pnpm
  npmPackages:
    @vitest/ui: latest => 3.0.9 
    vite: latest => 6.2.3 
    vitest: latest => 3.0.9

Used Package Manager

npm

Validations

@sheremet-va
Copy link
Member

Is there a way to implement a custom error serializer for vitest?

Yes. Define toJSON method on the error 🙂

@dmaretskyi
Copy link
Author

That results in this kind of formatting, which is functional, but leads to poor developer experience:

{
  tag: 'MY_ERROR',
  stackStr: 'Error: error message\n' +
    '    at throwError (/home/projects/vitest-dev-vitest-659jeds3/test/basic.test.ts:25:11)\n' +
    '    at eval (/home/projects/vitest-dev-vitest-659jeds3/test/basic.test.ts:28:3)\n' +
    '    at eval (file:///home/projects/vitest-dev-vitest-659jeds3/node_modules/@vitest/runner/dist/index.js:217:14)\n' +
    '    at eval (file:///home/projects/vitest-dev-vitest-659jeds3/node_modules/@vitest/runner/dist/index.js:608:28)\n' +
    '    at eval (file:///home/projects/vitest-dev-vitest-659jeds3/node_modules/@vitest/runner/dist/index.js:99:24)\n' +
    '    at https://vitestdevvitest659jeds3-lueh.w-credentialless-staticblitz.com/blitz.33edf5bb.js:40:25129\n' +
    '    at new Promise (<anonymous>)\n' +
    '    at new Promise (https://vitestdevvitest659jeds3-lueh.w-credentialless-staticblitz.com/blitz.33edf5bb.js:40:25088)\n' +
    '    at runWithTimeout (file:///home/projects/vitest-dev-vitest-659jeds3/node_modules/@vitest/runner/dist/index.js:76:12)\n' +
    '    at runTest (file:///home/projects/vitest-dev-vitest-659jeds3/node_modules/@vitest/runner/dist/index.js:1237:17)',
  nameStr: 'Error',
  expected: 'undefined',
  actual: 'undefined',
  stacks: [
    {
      method: 'throwError',
      file: '/home/projects/vitest-dev-vitest-659jeds3/test/basic.test.ts',
      line: 25,
      column: 11
    },
    {
      method: 'eval',
      file: '/home/projects/vitest-dev-vitest-659jeds3/test/basic.test.ts',
      line: 28,
      column: 3
    },
    { method: '', file: '/blitz.33edf5bb.js', line: 40, column: 25129 },
    {
      method: 'new Promise',
      file: '/blitz.33edf5bb.js',
      line: 40,
      column: 25088
    }
  ]
}

It's printed as a JS literal, with stack trace repeated 3 times with different formatting.

@sheremet-va
Copy link
Member

sheremet-va commented Apr 2, 2025

You didn't provide the message property, so Vitest fallbacks to printing the whole object (what else to print?). Both message and stack are not enumerable, so ...this doesn't add them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants