prisma / prisma

Next-generation ORM for Node.js & TypeScript | PostgreSQL, MySQL, MariaDB, SQL Server, SQLite, MongoDB and CockroachDB
https://www.prisma.io
Apache License 2.0
38.95k stars 1.53k forks source link

internal error: entered unreachable code #23407

Closed yaseenisolated closed 3 months ago

yaseenisolated commented 6 months ago

Hi Prisma Team! My Prisma Client just crashed. This is the report:

The code shown below gets this crash pretty consistently with concurrency set to 100

Versions

Name Version
Node v20.11.0
OS darwin-arm64
Prisma Client 5.10.2
Query Engine 5a9203d0590c951969e85a7d07215503f4672eb9
Database sqlite

I have also reproduced this on linux-x64

Logs


thread 'tokio-runtime-worker' panicked at libs/user-facing-errors/src/quaint.rs:167:18:
internal error: entered unreachable code
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
/Users/yaseenhamdulay/prisma-concurrency-test/node_modules/.pnpm/@prisma+client@5.10.2_prisma@5.10.2/node_modules/@prisma/client/runtime/library.js:123
`)}var Yi=({clientMethod:e,activeProvider:r})=>t=>{let n="",i;if(Array.isArray(t)){let[o,...s]=t;n=o,i={values:Ct(s||[]),__prismaRawParameters__:!0}}else switch(r){case"sqlite":case"mysql":{n=t.sql,i={values:Ct(t.values),__prismaRawParameters__:!0};break}case"cockroachdb":case"postgresql":case"postgres":{n=t.text,i={values:Ct(t.values),__prismaRawParameters__:!0};break}case"sqlserver":{n=el(t),i={values:Ct(t.values),__prismaRawParameters__:!0};break}default:throw new Error(`The ${r} provider does not support ${e}`)}return i?.values?il(`prisma.${e}(${n}, ${i.values})`):il(`prisma.${e}(${n})`),{query:n,parameters:i}},ol={requestArgsToMiddlewareArgs(e){return[e.strings,...e.values]},middlewareArgsToRequestArgs(e){let[r,...t]=e;return new oe(r,t)}},sl={requestArgsToMiddlewareArgs(e){return[e]},middlewareArgsToRequestArgs(e){return e[0]}};function Zi(e){return function(t){let n,i=(o=e)=>{try{return o===void 0||o?.kind==="itx"?n??(n=al(t(o))):al(t(o))}catch(s){return Promise.reject(s)}};return{then(o,s){return i().then(o,s)},catch(o){return i().catch(o)},finally(o){return i().finally(o)},requestTransaction(o){let s=i(o);return s.requestTransaction?s.requestTransaction(o):s},[Symbol.toStringTag]:"PrismaPromise"}}}function al(e){return typeof e.then=="function"?e:Promise.resolve(e)}var ll={isEnabled(){return!1},getTraceParent(){return"00-10-10-00"},async createEngineSpan(){},getActiveContext(){},runInChildSpan(e,r){return r()}},Xi=class{isEnabled(){return this.getGlobalTracingHelper().isEnabled()}getTraceParent(r){return this.getGlobalTracingHelper().getTraceParent(r)}createEngineSpan(r){return this.getGlobalTracingHelper().createEngineSpan(r)}getActiveContext(){return this.getGlobalTracingHelper().getActiveContext()}runInChildSpan(r,t){return this.getGlobalTracingHelper().runInChildSpan(r,t)}getGlobalTracingHelper(){return globalThis.PRISMA_INSTRUMENTATION?.helper??ll}};function ul(e){return e.includes("tracing")?new Xi:ll}function cl(e,r=()=>{}){let t,n=new Promise(i=>t=i);return{then(i){return--e===0&&t(r()),i?.(n)}}}var Qm=["$connect","$disconnect","$on","$transaction","$use","$extends"],pl=Qm;function ml(e){return typeof e=="string"?e:e.reduce((r,t)=>{let n=typeof t=="string"?t:t.level;return n==="query"?r:r&&(t==="info"||r==="info")?"info":n},void 0)}var Sn=class{constructor(){this._middlewares=[]}use(r){this._middlewares.push(r)}get(r){return this._middlewares[r]}has(r){return!!this._middlewares[r]}length(){return this._middlewares.length}};var fl=_(li());function Rn(e){return typeof e.batchRequestIdx=="number"}function An(e){return e===null?e:Array.isArray(e)?e.map(An):typeof e=="object"?Gm(e)?Jm(e):hr(e,An):e}function Gm(e){return e!==null&&typeof e=="object"&&typeof e.$type=="string"}function Jm({$type:e,value:r}){switch(e){case"BigInt":return BigInt(r);case"Bytes":return Buffer.from(r,"base64");case"DateTime":return new Date(r);case"Decimal":return new Te(r);case"Json":return JSON.parse(r);default:tr(r,"Unknown tagged value")}}function dl(e){if(e.action!=="findUnique"&&e.action!=="findUniqueOrThrow")return;let r=[];return e.modelName&&r.push(e.modelName),e.query.arguments&&r.push(eo(e.query.arguments)),r.push(eo(e.query.selection)),r.join("")}function eo(e){return`(${Object.keys(e).sort().map(t=>{let n=e[t];return typeof n=="object"&&n!==null?`(${t} ${eo(n)})`:t}).join(" ")})`}var Hm={aggregate:!1,aggregateRaw:!1,createMany:!0,createOne:!0,deleteMany:!0,deleteOne:!0,executeRaw:!0,findFirst:!1,findFirstOrThrow:!1,findMany:!1,findRaw:!1,findUnique:!1,findUniqueOrThrow:!1,groupBy:!1,queryRaw:!1,runCommandRaw:!0,updateMany:!0,updateOne:!0,upsertOne:!0};function ro(e){return Hm[e]}var In=class{constructor(r){this.options=r;this.tickActive=!1;this.batches={}}request(r){let t=this.options.batchBy(r);return t?(this.batches[t]||(this.batches[t]=[],this.tickActive||(this.tickActive=!0,process.nextTick(()=>{this.dispatchBatches(),this.tickActive=!1}))),new Promise((n,i)=>{this.batches[t].push({request:r,resolve:n,reject:i})})):this.options.singleLoader(r)}dispatchBatches(){for(let r in this.batches){let t=this.batches[r];delete this.batches[r],t.length===1?this.options.singleLoader(t[0].request).then(n=>{n instanceof Error?t[0].reject(n):t[0].resolve(n)}).catch(n=>{t[0].reject(n)}):(t.sort((n,i)=>this.options.batchOrder(n.request,i.request)),this.options.batchLoader(t.map(n=>n.request)).then(n=>{if(n instanceof Error)for(let i=0;i<t.length;i++)t[i].reject(n);else for(let i=0;i<t.length;i++){let o=n[i];o instanceof Error?t[i].reject(o):t[i].resolve(o)}}).catch(n=>{for(let i=0;i<t.length;i++)t[i].reject(n)}))}}get[Symbol.toStringTag](){return"DataLoader"}};var Wm=N("prisma:client:request_handler"),_n=class{constructor(r,t){this.logEmitter=t,this.client=r,this.dataloader=new In({batchLoader:na(async({requests:n,customDataProxyFetch:i})=>{let{transaction:o,otelParentCtx:s}=n[0],a=n.map(p=>p.protocolQuery),l=this.client._tracingHelper.getTraceParent(s),u=n.some(p=>ro(p.protocolQuery.action));return(await this.client._engine.requestBatch(a,{traceparent:l,transaction:Km(o),containsWrite:u,customDataProxyFetch:i})).map((p,m)=>{if(p instanceof Error)return p;try{return this.mapQueryEngineResult(n[m],p)}catch(f){return f}})}),singleLoader:async n=>{let i=n.transaction?.kind==="itx"?gl(n.transaction):void 0,o=await this.client._engine.request(n.protocolQuery,{traceparent:this.client._tracingHelper.getTraceParent(),interactiveTransaction:i,isWrite:ro(n.protocolQuery.action),customDataProxyFetch:n.customDataProxyFetch});return this.mapQueryEngineResult(n,o)},batchBy:n=>n.transaction?.id?`transaction-${n.transaction.id}`:dl(n.protocolQuery),batchOrder(n,i){return n.transaction?.kind==="batch"&&i.transaction?.kind==="batch"?n.transaction.index-i.transaction.index:0}})}async request(r){try{return await this.dataloader.request(r)}catch(t){let{clientMethod:n,callsite:i,transaction:o,args:s,modelName:a}=r;this.handleAndLogRequestError({error:t,clientMethod:n,callsite:i,transaction:o,args:s,modelName:a})}}mapQueryEngineResult({dataPath:r,unpacker:t},n){let i=n?.data,o=n?.elapsed,s=this.unpack(i,r,t);return process.env.PRISMA_CLIENT_GET_TIME?{data:s,elapsed:o}:s}handleAndLogRequestError(r){try{this.handleRequestError(r)}catch(t){throw this.logEmitter&&this.logEmitter.emit("error",{message:t.message,target:r.clientMethod,timestamp:new Date}),t}}handleRequestError({error:r,clientMethod:t,callsite:n,transaction:i,args:o,modelName:s}){if(Wm(r),zm(r,i)||r instanceof Le)throw r;if(r instanceof V&&Ym(r)){let l=hl(r.meta);Cn({args:o,errors:[l],callsite:n,errorFormat:this.client._errorFormat,originalMethod:t,clientVersion:this.client._clientVersion})}let a=r.message;if(n&&(a=Ar({callsite:n,originalMethod:t,isPanic:r.isPanic,showColors:this.client._errorFormat==="pretty",message:a})),a=this.sanitizeMessage(a),r.code){let l=s?{modelName:s,...r.meta}:r.meta;throw new V(a,{code:r.code,clientVersion:this.client._clientVersion,meta:l,batchRequestIdx:r.batchRequestIdx})}else{if(r.isPanic)throw new ue(a,this.client._clientVersion);if(r instanceof j)throw new j(a,{clientVersion:this.client._clientVersion,batchRequestIdx:r.batchRequestIdx});if(r instanceof S)throw new S(a,this.client._clientVersion);if(r instanceof ue)throw new ue(a,this.client._clientVersion)}throw r.clientVersion=this.client._clientVersion,r}sanitizeMessage(r){return this.client._errorFormat&&this.client._errorFormat!=="pretty"?(0,fl.default)(r):r}unpack(r,t,n){if(!r||(r.data&&(r=r.data),!r))return r;let i=Object.values(r)[0],o=t.filter(a=>a!=="select"&&a!=="include"),s=An(Ai(i,o));return n?n(s):s}get[Symbol.toStringTag](){return"RequestHandler"}};function Km(e){if(e){if(e.kind==="batch")return{kind:"batch",options:{isolationLevel:e.isolationLevel}};if(e.kind==="itx")return{kind:"itx",options:gl(e)};tr(e,"Unknown transaction kind")}}function gl(e){return{id:e.id,payload:e.payload}}function zm(e,r){return Rn(e)&&r?.kind==="batch"&&e.batchRequestIdx!==r.index}function Ym(e){return e.code==="P2009"||e.code==="P2012"}function hl(e){if(e.kind==="Union")return{kind:"Union",errors:e.errors.map(hl)};if(Array.isArray(e.selectionPath)){let[,...r]=e.selectionPath;return{...e,selectionPath:r}}return e}var yl="5.10.2";var El=yl;function bl(e){return e.map(r=>{let t={};for(let n of Object.keys(r))t[n]=wl(r[n]);return t})}function wl({prisma__type:e,prisma__value:r}){switch(e){case"bigint":return BigInt(r);case"bytes":return Buffer.from(r,"base64");case"decimal":return new Te(r);case"datetime":case"date":return new Date(r);case"time":return new Date(`1970-01-01T${r}Z`);case"array":return r.map(wl);default:return r}}var Tl=_(Hi());var q=class extends Error{constructor(r){super(r+`

PrismaClientRustPanicError:
Invalid `prisma.user.create()` invocation in
/Users/yaseenhamdulay/prisma-concurrency-test/test.js:7:23

  4 const createUser = async (j) => {
  5   for (var i = 0; i < 100; i++) {
  6     const r = Math.ceil(Math.random() * 100000);
→ 7     await prisma.user.create(
internal error: entered unreachable code

This is a non-recoverable error which probably happens when the Prisma Query Engine has a panic.
, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:client:libraryEngine sending request, this.libraryStarted: true
prisma:cli

Code

const { PrismaClient } = require("@prisma/client");
const prisma = new PrismaClient();

const createUser = async (j) => {
  for (var i = 0; i < 100; i++) {
    const r = Math.ceil(Math.random() * 100000);
    await prisma.user.create({
      data: {
        id: j * 10000 + i,
        name: r.toString(),
      },
    });
  }
};

const runTest = async (concurrentUsers) => {
  const promises = [];
  for (let i = 0; i < concurrentUsers; i++) {
    promises.push(createUser(i));
  }

  console.time("test");
  await Promise.all(promises);
  console.timeEnd("test");
};

runTest(10); // Test with 100 concurrent queries

Schema

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "sqlite"
  url      = "file:./dev.db"
}

model User {
  id   Int    @id
  name String
}
yaseenisolated commented 6 months ago

The backtrace isn't very useful. I should probably run it with debugging symbols?

thread 'tokio-runtime-worker' panicked at libs/user-facing-errors/src/quaint.rs:167:18:
internal error: entered unreachable code
stack backtrace:
   0:        0x1177a0e9c - _napi_register_module_v1
   1:        0x117095bb0 - <unknown>
   2:        0x117784574 - _napi_register_module_v1
   3:        0x1177a46c4 - _napi_register_module_v1
   4:        0x1177a4014 - _napi_register_module_v1
   5:        0x1177a4e7c - _napi_register_module_v1
   6:        0x1177a49d0 - _napi_register_module_v1
   7:        0x1177a4960 - _napi_register_module_v1
   8:        0x1177a4954 - _napi_register_module_v1
   9:        0x117ad6068 - _napi_register_module_v1
  10:        0x117ad6190 - _napi_register_module_v1
  11:        0x117828660 - _napi_register_module_v1
  12:        0x117739ad8 - _napi_register_module_v1
  13:        0x11775c260 - _napi_register_module_v1
  14:        0x117769b70 - _napi_register_module_v1
  15:        0x11757c0e8 - _napi_register_module_v1
  16:        0x11759c818 - _napi_register_module_v1
  17:        0x11759d128 - _napi_register_module_v1
  18:        0x116faa6e8 - <unknown>
  19:        0x116fac2b8 - <unknown>
  20:        0x116fca13c - <unknown>
  21:        0x116fc4f6c - <unknown>
  22:        0x116fb3664 - <unknown>
  23:        0x11701f14c - <unknown>
  24:        0x116febae4 - <unknown>
  25:        0x116ffc740 - <unknown>
  26:        0x1177bb334 - _napi_register_module_v1
  27:        0x1177c586c - _napi_register_module_v1
  28:        0x1177b96c0 - _napi_register_module_v1
  29:        0x1177b9140 - _napi_register_module_v1
  30:        0x1177bf1a4 - _napi_register_module_v1
  31:        0x1177a5db8 - _napi_register_module_v1
  32:        0x183bc5034 - __pthread_joiner_wake
yaseenisolated commented 6 months ago

Ah. I had a mistake in my test harness. looks like this only consistently crashes around concurrency level 100.

Weakky commented 6 months ago

Hey @yaseenisolated, thanks for reporting. Just to confirm, does the snippet you shared consistently reproduce the bug? Thank you!

yaseenisolated commented 6 months ago

Pretty consistently. I would say half the time if you set the concurrency to 100

janpio commented 6 months ago

Note that there might be related issues for SQLite under https://github.com/prisma/prisma/issues?q=is%3Aopen+label%3A%22topic%3A+Promise.all%22+sort%3Aupdated-desc

jkomyno commented 3 months ago

Hi @yaseenisolated, we believe we have a fix for this issue.

We plan on releasing it with the next stable version of Prisma (5.16.0), but in the meantime, we'd like to collect some early feedback directly from the impacted users. Can you please try installing Prisma 5.16.0-integration-sqlite-fix.1, and confirm that you can no longer experience this bug with it? Thanks!

pnpm install -D prisma@5.16.0-integration-sqlite-fix.1
pnpm install @prisma/client@5.16.0-integration-sqlite-fix.1

(Please note that this Prisma version is unstable, so we don't recommend running it in production.)

jkomyno commented 3 months ago

Hello! This issue was solved via https://github.com/prisma/prisma-engines/pull/4907. The fix is already available on Prisma 5.15.1.

Please make sure you update the prisma CLI, the @prisma/client library, and run prisma generate again :)