Skip to content
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

Vitest crashes when running tests with Prisma #3106

Closed
6 tasks done
nakleiderer opened this issue Mar 30, 2023 · 16 comments
Closed
6 tasks done

Vitest crashes when running tests with Prisma #3106

nakleiderer opened this issue Mar 30, 2023 · 16 comments

Comments

@nakleiderer
Copy link

nakleiderer commented Mar 30, 2023

Describe the bug

NOTE: I'm cross-posting this issue from prisma/prisma#18577 because it's unclear which tool is causing the issue, the bug might require collaboration between vitest and prisma, and for other members of the vitest or prisma communities to be able to search this issue in their respective repositories.

When running tests with Vitest and Prisma, I receive a variety of crashes: segmentation fault, bus error, and abort. Sometimes, Rust is able to print a stack trace before crashing:

Super long debug output and stack trace
❯ npm run test -- --run

> vitest-crash-reproduction@0.0.0 test
> vitest --run

  vite:config bundled config file loaded in 24.26ms +0ms
  vite:esbuild init tsconfck (root: /vitest-crash-reproduction) +0ms
  vite:esbuild init tsconfck (root: /vitest-crash-reproduction) +0ms
  vite:esbuild init tsconfck end +1ms
  vite:esbuild init tsconfck end +0ms
  vite:config using resolved config: {
  vite:config   test: {},
  vite:config   logLevel: 'error',
  vite:config   configFile: '/vitest-crash-reproduction/vite.config.ts',
  vite:config   mode: 'test',
  vite:config   plugins: [
  vite:config     'vite:pre-alias',
  vite:config     'alias',
  vite:config     'vitest',
  vite:config     'vitest:env-replacer',
  vite:config     'vitest:global-setup-plugin',
  vite:config     'vitest:css-disable',
  vite:config     'vite:modulepreload-polyfill',
  vite:config     'vite:resolve',
  vite:config     'vite:html-inline-proxy',
  vite:config     'vite:css',
  vite:config     'vite:esbuild',
  vite:config     'vite:json',
  vite:config     'vite:wasm-helper',
  vite:config     'vite:worker',
  vite:config     'vite:asset',
  vite:config     'vitest:coverage-transform',
  vite:config     'vite:wasm-fallback',
  vite:config     'vite:define',
  vite:config     'vite:css-post',
  vite:config     'vite:worker-import-meta-url',
  vite:config     'vite:asset-import-meta-url',
  vite:config     'vite:dynamic-import-vars',
  vite:config     'vite:import-glob',
  vite:config     'vitest:css-empty-post',
  vite:config     'vite:client-inject',
  vite:config     'vite:import-analysis'
  vite:config   ],
  vite:config   esbuild: { sourcemap: 'external', legalComments: 'inline' },
  vite:config   resolve: {
  vite:config     mainFields: [],
  vite:config     browserField: false,
  vite:config     conditions: [ 'node' ],
  vite:config     extensions: [
  vite:config       '.mjs',  '.js',
  vite:config       '.mts',  '.ts',
  vite:config       '.jsx',  '.tsx',
  vite:config       '.json'
  vite:config     ],
  vite:config     dedupe: [],
  vite:config     preserveSymlinks: false,
  vite:config     alias: [ [Object], [Object] ]
  vite:config   },
  vite:config   server: {
  vite:config     preTransformRequests: false,
  vite:config     watch: { persistent: false, depth: 0, ignored: [Array] },
  vite:config     open: undefined,
  vite:config     hmr: false,
  vite:config     middlewareMode: false,
  vite:config     fs: { strict: true, allow: [Array], deny: [Array] }
  vite:config   },
  vite:config   css: { modules: { generateScopedName: [Function (anonymous)] } },
  vite:config   optimizeDeps: {
  vite:config     disabled: true,
  vite:config     entries: [],
  vite:config     esbuildOptions: { preserveSymlinks: false }
  vite:config   },
  vite:config   configFileDependencies: [
  vite:config     '/vitest-crash-reproduction/vite.config.ts'
  vite:config   ],
  vite:config   inlineConfig: {
  vite:config     logLevel: 'error',
  vite:config     configFile: '/vitest-crash-reproduction/vite.config.ts',
  vite:config     mode: 'test',
  vite:config     plugins: [ [Object], [Object], [Object], [Object], [Object], [Object] ]
  vite:config   },
  vite:config   root: '/vitest-crash-reproduction',
  vite:config   base: '/',
  vite:config   publicDir: '/vitest-crash-reproduction/public',
  vite:config   cacheDir: '/vitest-crash-reproduction/node_modules/.vite',
  vite:config   command: 'serve',
  vite:config   ssr: {
  vite:config     format: 'esm',
  vite:config     target: 'node',
  vite:config     optimizeDeps: { disabled: true, esbuildOptions: [Object] }
  vite:config   },
  vite:config   isWorker: false,
  vite:config   mainConfig: null,
  vite:config   isProduction: false,
  vite:config   build: {
  vite:config     target: [ 'es2020', 'edge88', 'firefox78', 'chrome87', 'safari13' ],
  vite:config     cssTarget: [ 'es2020', 'edge88', 'firefox78', 'chrome87', 'safari13' ],
  vite:config     outDir: 'dist',
  vite:config     assetsDir: 'assets',
  vite:config     assetsInlineLimit: 4096,
  vite:config     cssCodeSplit: true,
  vite:config     sourcemap: false,
  vite:config     rollupOptions: {},
  vite:config     minify: 'esbuild',
  vite:config     terserOptions: {},
  vite:config     write: true,
  vite:config     emptyOutDir: null,
  vite:config     copyPublicDir: true,
  vite:config     manifest: false,
  vite:config     lib: false,
  vite:config     ssr: false,
  vite:config     ssrManifest: false,
  vite:config     reportCompressedSize: true,
  vite:config     chunkSizeWarningLimit: 500,
  vite:config     watch: null,
  vite:config     commonjsOptions: { include: [Array], extensions: [Array] },
  vite:config     dynamicImportVarsOptions: { warnOnError: true, exclude: [Array] },
  vite:config     modulePreload: { polyfill: true }
  vite:config   },
  vite:config   preview: {
  vite:config     port: undefined,
  vite:config     strictPort: undefined,
  vite:config     host: undefined,
  vite:config     https: undefined,
  vite:config     open: undefined,
  vite:config     proxy: undefined,
  vite:config     cors: undefined,
  vite:config     headers: undefined
  vite:config   },
  vite:config   env: { BASE_URL: '/', MODE: 'test', DEV: true, PROD: false },
  vite:config   assetsInclude: [Function: assetsInclude],
  vite:config   logger: {
  vite:config     hasWarned: false,
  vite:config     info: [Function: info],
  vite:config     warn: [Function: warn],
  vite:config     warnOnce: [Function: warnOnce],
  vite:config     error: [Function: error],
  vite:config     clearScreen: [Function: clearScreen],
  vite:config     hasErrorLogged: [Function: hasErrorLogged]
  vite:config   },
  vite:config   packageCache: Map(0) {},
  vite:config   createResolver: [Function: createResolver],
  vite:config   worker: {
  vite:config     format: 'iife',
  vite:config     plugins: [
  vite:config       'vite:pre-alias',
  vite:config       'alias',
  vite:config       'vite:modulepreload-polyfill',
  vite:config       'vite:resolve',
  vite:config       'vite:html-inline-proxy',
  vite:config       'vite:css',
  vite:config       'vite:esbuild',
  vite:config       'vite:json',
  vite:config       'vite:wasm-helper',
  vite:config       'vite:worker',
  vite:config       'vite:asset',
  vite:config       'vite:wasm-fallback',
  vite:config       'vite:define',
  vite:config       'vite:css-post',
  vite:config       'vite:worker-import-meta-url',
  vite:config       'vite:asset-import-meta-url',
  vite:config       'vite:dynamic-import-vars',
  vite:config       'vite:import-glob',
  vite:config       'vite:client-inject',
  vite:config       'vite:import-analysis'
  vite:config     ],
  vite:config     rollupOptions: {},
  vite:config     getSortedPlugins: [Function: getSortedPlugins],
  vite:config     getSortedPluginHooks: [Function: getSortedPluginHooks]
  vite:config   },
  vite:config   appType: 'spa',
  vite:config   experimental: { importGlobRestoreExtension: false, hmrPartialAccept: false },
  vite:config   getSortedPlugins: [Function: getSortedPlugins],
  vite:config   getSortedPluginHooks: [Function: getSortedPluginHooks]
  vite:config } +4ms
  connect:dispatcher use / viteTimeMiddleware +0ms
  connect:dispatcher use / corsMiddleware +0ms
  connect:dispatcher use /__open-in-editor launchEditorMiddleware +0ms
  connect:dispatcher use / viteServePublicMiddleware +0ms
  connect:dispatcher use / viteTransformMiddleware +0ms
  connect:dispatcher use / viteServeRawFsMiddleware +0ms
  connect:dispatcher use / viteServeStaticMiddleware +0ms
  connect:dispatcher use / viteHtmlFallbackMiddleware +0ms
  connect:dispatcher use / viteIndexHtmlMiddleware +0ms
  connect:dispatcher use / vite404Middleware +0ms
  connect:dispatcher use / viteErrorMiddleware +0ms

 RUN  v0.29.8 /vitest-crash-reproduction

  vite-node:server:request /@vite/env +0ms
  vite:resolve 0.86ms /@vite/env -> /vitest-crash-reproduction/node_modules/vite/dist/client/env.mjs +0ms
  vite:load 0.66ms [fs] /@vite/env +0ms
  vite:import-analysis 0.15ms [no imports] node_modules/vite/dist/client/env.mjs +0ms
  vite:transform 4.21ms /@vite/env +0ms
  vite:resolve 0.78ms vitest -> /vitest-crash-reproduction/node_modules/vitest/dist/index.js +15ms
2023-03-30T14:59:19.722Z vite-node:client:execute /@vite/env
2023-03-30T14:59:19.755Z vite-node:client:native /vitest-crash-reproduction/node_modules/vitest/dist/runners.js
  vite-node:server:request /vitest-crash-reproduction/test/reproduction.test.ts +54ms
  vite:load 0.27ms [fs] test/reproduction.test.ts +51ms
  vite:import-analysis 1.30ms [0 imports rewritten] test/reproduction.test.ts +51ms
  vite:transform 3.50ms test/reproduction.test.ts +50ms
2023-03-30T14:59:19.766Z vite-node:client:execute /vitest-crash-reproduction/test/reproduction.test.ts
  vite:resolve 0.55ms @prisma/client -> /vitest-crash-reproduction/node_modules/@prisma/client/index.js +45ms
2023-03-30T14:59:19.768Z vite-node:client:native /vitest-crash-reproduction/node_modules/@prisma/client/index.js
2023-03-30T14:59:19.783Z prisma:tryLoadEnv  Environment variables not found at null
2023-03-30T14:59:19.783Z prisma:tryLoadEnv  Environment variables not found at undefined
2023-03-30T14:59:19.783Z prisma:tryLoadEnv  No Environment variables loaded
2023-03-30T14:59:19.785Z vite-node:client:native /vitest-crash-reproduction/node_modules/vitest/dist/index.js
2023-03-30T14:59:19.788Z prisma:tryLoadEnv  Environment variables not found at null
2023-03-30T14:59:19.788Z prisma:tryLoadEnv  Environment variables not found at undefined
2023-03-30T14:59:19.788Z prisma:tryLoadEnv  No Environment variables loaded
2023-03-30T14:59:19.788Z prisma:client  dirname /vitest-crash-reproduction/node_modules/.prisma/client
2023-03-30T14:59:19.788Z prisma:client  relativePath ../../../prisma
2023-03-30T14:59:19.788Z prisma:client  cwd /vitest-crash-reproduction/prisma
2023-03-30T14:59:19.789Z prisma:client  protocol graphql
2023-03-30T14:59:19.789Z prisma:client  clientVersion 4.12.0
2023-03-30T14:59:19.789Z prisma:client  clientEngineType library
2023-03-30T14:59:19.789Z prisma:client:libraryEngine  internalSetup
2023-03-30T14:59:19.790Z prisma:client:libraryEngine:loader  Searching for Query Engine Library in /vitest-crash-reproduction/node_modules/.prisma/client
2023-03-30T14:59:19.791Z prisma:client:libraryEngine:loader  loadEngine using /vitest-crash-reproduction/node_modules/.prisma/client/libquery_engine-darwin-arm64.dylib.node
2023-03-30T14:59:19.796Z prisma:client:libraryEngine  library starting
2023-03-30T14:59:19.803Z prisma:client:libraryEngine  library started
 · test/reproduction.test.ts (1)
2023-03-30T14:59:19.810Z prisma:client  Prisma Client call:
2023-03-30T14:59:19.811Z prisma:client  prisma.user.count({
  select: {
    _count: {
      select: {
        _all: true
      }
    }
  },
  where: {
    id: 1
  }
})
2023-03-30T14:59:19.811Z prisma:client  Generated request:
2023-03-30T14:59:19.811Z prisma:client  query {
  aggregateUser(where: {
    id: 1
  }) {
    _count {
      _all
    }
  }
}

2023-03-30T14:59:19.811Z prisma:client:libraryEngine  sending request, this.libraryStarted: true
2023-03-30T14:59:19.811Z prisma:client  Prisma Client call:
2023-03-30T14:59:19.811Z prisma:client  prisma.user.count({
  select: {
    _count: {
      select: {
        _all: true
      }
    }
  },
  where: {
    id: 1
  }
})
2023-03-30T14:59:19.811Z prisma:client  Generated request:
2023-03-30T14:59:19.812Z prisma:client  query {
  aggregateUser(where: {
    id: 1
  }) {
    _count {
      _all
    }
  }
}

 ❯ test/reproduction.test.ts (1)
   × likely crashes

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

 FAIL  test/reproduction.test.ts > likely crashes
Error: Oh no!
 ❯ test/reproduction.test.ts:16:20
     14| 
     15|     // The issue seems related to a rejected promise happening while a query is running.
     16|     Promise.reject(new Error("Oh no!")),
       |                    ^
     17| 
     18|     // This line seems to make it more likely to crash, but it still does crash without it.

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

 Test Files  1 failed (1)
      Tests  1 failed (1)
   Start at  09:59:19
   Duration  229ms (transform 23ms, setup 0ms, collect 32ms, tests 17ms)

thread 'tokio-runtime-worker' panicked at 'Expected weak reference to be valid.', query-engine/schema/src/lib.rs:38:24
stack backtrace:
   0:        0x139511ae4 - _napi_register_module_v1
   1:        0x138ed6510 - <unknown>
   2:        0x1394f0354 - _napi_register_module_v1
   3:        0x139514f2c - _napi_register_module_v1
   4:        0x139514b8c - _napi_register_module_v1
   5:        0x139515a74 - _napi_register_module_v1
   6:        0x1395155f0 - _napi_register_module_v1
   7:        0x139515560 - _napi_register_module_v1
   8:        0x13951553c - _napi_register_module_v1
   9:        0x1397995bc - _napi_register_module_v1
  10:        0x138eda1b4 - <unknown>
  11:        0x138eda178 - <unknown>
  12:        0x1397997b8 - _napi_register_module_v1
  13:        0x1394192c0 - _napi_register_module_v1
  14:        0x139342fcc - _napi_register_module_v1
  15:        0x139342768 - _napi_register_module_v1
  16:        0x138e03ef4 - <unknown>
  17:        0x138e05098 - <unknown>
  18:        0x138e1d9e8 - <unknown>
  19:        0x138e1c284 - <unknown>
  20:        0x138e0c470 - <unknown>
  21:        0x138e5a9f0 - <unknown>
  22:        0x138e39988 - <unknown>
  23:        0x138e44a70 - <unknown>
  24:        0x13952c3c0 - _napi_register_module_v1
  25:        0x1395378c4 - _napi_register_module_v1
  26:        0x13952b33c - _napi_register_module_v1
  27:        0x13952ad58 - _napi_register_module_v1
  28:        0x139530e3c - _napi_register_module_v1
  29:        0x139516e24 - _napi_register_module_v1
  30:        0x1b120606c - __pthread_deallocate
zsh: bus error  npm run test -- --run

In Prisma 4.11, I also received this trace (but was unable to get it again with 4.12):

thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `1`,
 right: `0`: failed to delete napi ref', query-engine/query-engine-node-api/src/engine.rs:140:1
stack backtrace:
   0:        0x116d0a4f8 - _napi_register_module_v1
   1:        0x1166d0604 - <unknown>
   2:        0x116ce8604 - _napi_register_module_v1
   3:        0x116d0d944 - _napi_register_module_v1
   4:        0x116d0d5a4 - _napi_register_module_v1
   5:        0x116d0e47c - _napi_register_module_v1
   6:        0x116d0e008 - _napi_register_module_v1
   7:        0x116d0df78 - _napi_register_module_v1
   8:        0x116d0df54 - _napi_register_module_v1
   9:        0x116f8e98c - _napi_register_module_v1
  10:        0x116f8eb70 - _napi_register_module_v1
  11:        0x116f90ad8 - _napi_register_module_v1
  12:        0x11663ad34 - <unknown>
fatal runtime error: failed to initiate panic, error 5

The issue seems to be related to Vitest's threading features. If you set test: { threads: false } in the vite.config.ts, the issue no longer occurs (or becomes so rare that I've been unable to find a failure).

It's unclear to me if the root cause is in Vitest or Prisma, or perhaps a subtle interaction between the projects. I've tested Prisma v3.15 through 4.12 with Vitest 0.29.8 and received similar crashes. I've tested Vitest 0.24.0 through 0.29.8 and v0.24.4 appears to be the first affected version of vitest.

Potentially related issues:

Reproduction

  1. Clone the reproduction repo: nakleiderer/vitest-crash-reproduction
  2. Setup a local postgres server able to respond to this connection string: postgresql://postgres:postgres@localhost:5432/postgres
    (or change the connection string in prisma/schema.prisma)
  3. Run npm install and npx prisma migrate
  4. Run 'npm test' (for watch mode) or npm test -- --run (for single test run)
  5. See error (you might need to repeat step 4, as this issue appears to depend on a race condition)

System Info

System:
    OS: macOS 13.2.1 (22D68)
    CPU: (10) arm64 Apple M1 Max
    Memory: 2.16 GB / 64.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 18.13.0 - ~/.asdf/installs/nodejs/18.13.0/bin/node
    npm: 8.19.3 - ~/.asdf/plugins/nodejs/shims/npm
  Browsers:
    Chrome: 111.0.5563.146
    Firefox: 108.0.1
    Safari: 16.3
  npmPackages:
    @prisma/client: ^4.12.0 => 4.12.0 
    prisma: ^4.12.0 => 4.12.0 
    vitest: ^0.29.8 => 0.29.8 

Used Package Manager

npm

Validations

@rcbevans
Copy link

rcbevans commented Apr 2, 2023

I'm seeing this issue causing intermittent CI failures when running tests with

    "vite": "^4.2.1",
    "vitest": "^0.29.8",
    "@prisma/client": "^4.12.0",
    "prisma": "^4.12.0",

@bodinsamuel
Copy link
Contributor

I have the same issue, removing manual $connect makes the test run "correctly" but there is no obvious reason it should run correctly except than it is silently erroring.

@nakleiderer
Copy link
Author

I have the same issue, removing manual $connect makes the test run "correctly" but there is no obvious reason it should run correctly except than it is silently erroring.

I made the same observation. It's my assumption that removing the manual connect sometimes allows the test to run correctly because the connection to the database hasn't been established before the rejection is processed. So, the query never really begins executing in this case. I put the connect in the test to ensure that the query has the best chance of executing.

@nakleiderer
Copy link
Author

I tested again with prisma 4.12.0 and vitest 0.30.1 and received the same results

@phifa
Copy link

phifa commented Apr 25, 2023

have the same issue, hard to spot, so many variations of it. now trying with threads: false, looks promising. but i assume a performance hit @nakleiderer ?

@nakleiderer
Copy link
Author

nakleiderer commented Apr 25, 2023

but i assume a performance hit @nakleiderer ?

@phifa Yes, quite a big one, especially if you have a decent machine and some longer running async tests.

@nakleiderer
Copy link
Author

I tested again with prisma v4.13.0 and vitest v0.31.0 and received similar crashes with the reproduction repo.

@janhesters
Copy link

janhesters commented May 14, 2023

Same here, happens with Prisma tests. thread: false fixes it, even if it slows down overall test execution. (Our tests are set up to be parallelizable).

@AriPerkkio
Copy link
Member

Does anyone have a minimal reproduction case that I could run without installing non-Node dependencies, e.g. postgresql? Something as simple as npm install && npm test?

It sounds like Prisma isn't stable when run in node:worker_threads. There might be some work-arounds but I'd need to be able to reproduce this issue locally for testing those.

@nakleiderer
Copy link
Author

nakleiderer commented May 17, 2023

@AriPerkkio you can adapt my repro to use sqlite instead, I'm pretty sure it also fails. https://github.com/nakleiderer/vitest-crash-reproduction

You'll need to change the prisma/schema.prisma according to prisma's docs https://www.prisma.io/docs/concepts/database-connectors/sqlite

EDIT: I added a sqlite branch to the repro.

@nakleiderer
Copy link
Author

I added a sqlite branch to the repro. It appears that this makes the errors less common. My suspicion is that Prisma's connection cleanup is the culprit and the local sqlite version doesn't experience it as often because it's super easy to cleanup.

@AriPerkkio
Copy link
Member

AriPerkkio commented May 18, 2023

Thanks @nakleiderer for reproduction setups. I hadn't noticed that there was a ready-to-use Docker setup for database. I was able to reproduce the issue constantly with that one.

Here is minimal reproduction without Vitest. Prisma keeps crashing constantly with errors like:

  • Segmentation fault: 11
  • Bus error: 10
  • Abort trap: 6
  • thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
      left: `1`,
     right: `0`: failed to delete napi ref', query-engine/query-engine-node-api/src/engine.rs:137:1
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    fatal runtime error: failed to initiate panic, error 5
    Abort trap: 6
    
  • Bus error: 10
  • thread 'tokio-runtime-worker' panicked at 'internal error: entered unreachable code', /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.25.0/src/sync/rwlock.rs:441:13
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    Abort trap: 6
    
  • thread 'tokio-runtime-worker' panicked at 'internal error: entered unreachable code: Function("P\u{da2e}\u{1}\0\0\0\0\0\0\0\0", ArgumentsList { arguments: [], empty_arguments: [], trailing_comma: None }, Span { start: 249, end: 264 })', query-engine/dml/src/lift.rs:71:18
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    node(13369,0x17ad97000) malloc: Double free of object 0x12eebc0b0
    node(13369,0x17ad97000) malloc: *** set a breakpoint in malloc_error_break to debug
    Abort trap: 6
    

Save this as repro.mjs and run it like node repro.mjs. Use the dependencies from https://github.com/nakleiderer/vitest-crash-reproduction/tree/main.

import { Worker, isMainThread } from "node:worker_threads";
import { resolve } from "node:path";
import { PrismaClient } from "@prisma/client";

if (isMainThread) {
  // Run 10x workers. The crash is noticeable with lower amounts too.
  for (const _ of Array(10).fill()) {
    new Worker(resolve("./worker.mjs"));
  }
} else {
  const prisma = new PrismaClient();

  await prisma.$connect();

  await Promise.all([
    prisma.user.count({ where: { id: 1 } }),
    Promise.reject(new Error("Oh no!")),
    prisma.user.count({ where: { id: 1 } }),
  ])
    // Catching the error does not matter
    .catch(() => {});

  // Disconnection does not matter
  // await prisma.$disconnect();
}

@nakleiderer
Copy link
Author

@AriPerkkio Great work! Thank you. I certainly appreciate your time. I'll open a new reproduction and send it over to the Prisma team on this issue prisma/prisma#18577

It seems like this is clearly in the Prisma ballpark now (unless they don't support workers, but we'll find out). Did something change in vitest around v0.24.4 that would have made this issue more noticeable? Is there any configuration available in vitest to disable worker isolation but still allow some concurrency, or is thread:false the best option for now?

@AriPerkkio
Copy link
Member

I would recommend to use poolMatchGlobs for moving only the required test cases in to the child_process and keep every other test running in worker_threads as usual:

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    poolMatchGlobs: [
      // Run database tests in child_process - Prisma crashes when run in 'node:worker_threads'
      ['**/database/tests/**', 'child_process'],
    ]
  }
})

If Prisma does not support node:worker_threads, I think they should detect this using import { isMainThread } from 'node:worker_threads' and display an error.

@janpio
Copy link

janpio commented Jun 5, 2023

Thanks for the help investigating this @AriPerkkio.

@AriPerkkio
Copy link
Member

Fixed by #3925 and #4172.

Vitest 1.0.0-beta has now --pool=forks which uses multiple node:child_process in parallel. The previous --no-threads was using a single node:child_process.

If the code you are testing is incompatible with node:worker_threads, switch to --pool=forks. If you run into same error with that pool, feel free to open new issue with minimal reproduction.

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

No branches or pull requests

7 participants