Repository navigation
adapter-pg: PgTransaction.performIO called concurrently on single pg Client during update with multiple include relations, triggering deprecation warning #29407
Description
Bug description
When using @prisma/adapter-pg with Prisma 7, the following deprecation warning is emitted at runtime when an update is run, with multiple includes (see below for detailed example and detailed logs)
Calling client.query() when the client is already executing a query is deprecated
and will be removed in pg@9.0. Use async/await or an external async flow control
mechanism instead.
I think the Array.map in interpretNode is dispatching multiple performIO calls concurrently onto the same PgTransaction client. Since PgTransaction holds a single pg Client (not a Pool), concurrent client.query() calls on it trigger the deprecation.
This will become a hard error in pg@9.0.
Severity
🔹 Minor: Unexpected behavior, but does not block development
Reproduction
An update with multiple include relations triggers it reliably (see below).
Notes:
- The warning does not originate from user code — confirmed by full stack trace
- Passing an explicit
pg.Poolwithmax > 1toPrismaPgdoes not resolve it - Does not reproduce on
findUniquewith a similarincludeshape — appears specific to write operations that open an implicit transaction and then fetch relations on the same connection
Expected vs. Actual Behavior
Expected: - Shouldn't log a warning (will break in next pg major version)
Actual Behavior: - Shows a warning (see below)
Frequency
Consistently reproducible
Does this occur in development or production?
Both development and production
Is this a regression?
Warning occurs since pg 8.20.0 (via Prisma 7.5), but behavior is unchanged on Prisma's side.
Workaround
Downgrade to pg to 8.18
Prisma Schema & Queries
model Parent {
id String @id @default(cuid())
RelationA SomeRelationA[]
RelationB SomeRelationB[]
RelationC SomeRelationC[]
}
model SomeRelationA {
id String @id @default(cuid())
parentId String
Parent Parent @relation(fields: [parentId], references: [id])
}
model SomeRelationB {
// Similar as above
}
model SomeRelationC {
// Similar as above
}await prisma.parent.update({
where: { id: args.id },
data: {},
include: {
RelationA: { orderBy: { order: 'asc' } },
RelationB: { orderBy: { order: 'asc' } },
RelationC: { orderBy: { order: 'asc' } },
},
})Prisma Config
export default {
schema: path.join('prisma', 'schema'),
migrations: {
path: path.join('prisma', 'migrations'),
seed: 'tsx prisma/seed',
},
datasource: DATABASE_URL ? { url: DATABASE_URL } : undefined,
} satisfies PrismaConfigLogs & Debug Info
Calling client.query() when the client is already executing a query is deprecated and will be removed in pg@9.0. Use async/await or an external async flow control mechanism instead.
DeprecationWarning: Calling client.query() when the client is already executing a query is deprecated and will be removed in pg@9.0. Use async/await or an external async flow control mechanism instead.
at Client.query (/MY_PATH/node_modules/pg/lib/client.js:691:7)
at PgTransaction.performIO (/MY_PATH/.next/dev/server/chunks/ssr/[root-of-the-server]__044le1t._.js:4548:46)
at PgTransaction.queryRaw (/MY_PATH/.next/dev/server/chunks/ssr/[root-of-the-server]__044le1t._.js:4500:45)
at /MY_PATH/node_modules/@prisma/client/runtime/client.js:11:44617
at xr (/MY_PATH/node_modules/@prisma/client/runtime/client.js:11:26620)
at #u (/MY_PATH/node_modules/@prisma/client/runtime/client.js:11:47917)
at e.interpretNode (/MY_PATH/node_modules/@prisma/client/runtime/client.js:11:44586)
at /MY_PATH/node_modules/@prisma/client/runtime/client.js:11:45739
at Array.map (<anonymous>)
at e.interpretNode (/MY_PATH/node_modules/@prisma/client/runtime/client.js:11:45688)
at process.processTicksAndRejections (node:internal/process/task_queues:103:5)
Environment & Setup
- OS: macOs Tahoe 26.3 (25D125)
- Database: Postgres 15
- Node.js version: v24.13.0
Also happens in prod on Vercel with Node 24
Prisma Version
prisma : 7.5.0
@prisma/client : 7.5.0
Operating System : darwin
Architecture : arm64
Node.js : v24.13.0
TypeScript : 6.0.2
Query Compiler : enabled
PSL : @prisma/prisma-schema-wasm 7.5.0-15.280c870be64f457428992c43c1f6d557fab6e29e
Schema Engine : schema-engine-cli 280c870be64f457428992c43c1f6d557fab6e29e (at node_modules/@prisma/engines/schema-engine-darwin-arm64)
Default Engines Hash : 280c870be64f457428992c43c1f6d557fab6e29e
Studio : 0.21.1
Preview Features : typedSql, views
Activity
fix(client-engine-runtime): serialize join children inside transactions
fix(adapter-pg): serialize concurrent transaction queries with a mutex
fix(client-engine-runtime): serialize join children inside transactions
fix(adapter-pg): serialize concurrent transaction queries with a mutex
fix(adapter-pg): serialize concurrent transaction queries with a mutex
maiconsanson commentedon May 30, 2026
I'm seeing the same warning with:
prisma 7.8.0@prisma/client 7.8.0@prisma/adapter-pg 7.8.0pg 8.21.0All database access goes through Prisma Client. I don't use
pool.connect()orclient.query()directly.The warning appears intermittently in both development and production:
I'm using
PrismaPgwith a sharedpg.Pool:Victorcassiano commentedon Jul 7, 2026
I am facing the same situation as well.
"prisma": "^7.8.0", "@prisma/client": "^7.8.0", "@prisma/adapter-pg": "^7.8.0", "pg": "^8.21.0",2026-07-07 15:33:05.166 [error] (node:4) DeprecationWarning: Calling client.query() when the client is already executing a query is deprecated and will be removed in pg@9.0. Use async/await or an external async flow control mechanism instead.` import { PrismaPg } from "@prisma/adapter-pg";
import { env } from "@/lib/config/env";
import { PrismaClient } from "./prisma/generated/prisma/client";
const globalForPrisma = globalThis as unknown as { prisma?: PrismaClient };
const adapter = new PrismaPg({
connectionString: env.DATABASE_URL,
max: 2,
idleTimeoutMillis: 10_000,
});
const prisma = globalForPrisma.prisma ?? new PrismaClient({ adapter });
if (process.env.NODE_ENV !== "production") {
globalForPrisma.prisma = prisma;
}
export { prisma }; `
gadcam commentedon Aug 11, 2026
Also hitting this on 7.9.1 with
@prisma/adapter-pg. One data point that widens the scope: it isn't specific to write operations.A plain
findUniquereproduces reliably when it runs inside an explicit interactive transaction:The warning fires between the call and its resolution — inside the single
await— so no userland concurrency is involved.The unifying factor looks like "executes on a single dedicated connection" rather than read vs. write:
findUniqueon the pool → each child query from thejoinnode gets its own pooled connection → no warningincludes → implicit transaction → one connection → warning$transaction→ one connection → warningThis lines up with @aqrln's point on #29468 that the constraint is about
pg.PoolClientgenerally rather than transactions specifically — a read inside a transaction reproducing is another sign it tracks the connection, not the operation type.Worth noting for anyone else landing here: serializing queries at the Prisma Client level (proxying the
txclient) does not suppress this, since the fan-out happens ininterpretNode, below the public API.Investigated and written with Claude.
fix(adapter-pg): serialize queries on single-connection clients
Romain-Devillez commentedon Aug 21, 2026
Confirming this from a production incident on our side (Prisma 7.9.1,
@prisma/adapter-pg7.9.1,pg8.22.0), with the exact same stack shape:Same trigger:
create()with threeincluded relations. A couple of data points that might be useful for #29468:findUnique/findManywith the sameincludeshape never reproduces it, since those run through the pool (each relation query gets its own connection) rather than a single transaction client.pg's own check isthis._queryQueue.length > 0before enqueuing — seeclient.js). We patched a local probe to flag a query issued while another was still active (i.e. the 2nd one, not just the 3rd+), and confirmed a write with only 2included relations also stacks two concurrent queries on the transaction client — it just stays underpg's current warning threshold. So the practical blast radius of this bug is every write with 2+ relations ininclude/select, not just 3+; the 3-relation case is simply the first one that becomes visible today. Worth keeping in mind for the fix in fix(adapter-pg): serialize queries within a transaction #29468, since pg@9 turns any concurrency on a busy client into a hard error regardless of count.Happy to share more repro details if useful.
gadcam commentedon Aug 21, 2026
Thanks @Romain-Devillez the
_queryQueue.length > 0detail is a useful confirmation that 2 relations already stack two queries.One correction though: it isn't specific to writes.
A
findUniquewith the same include shape inside an explicit$transactionreproduces reliably, reads only escape it when they run on the pool, which gives each child query its own connection.#29979 fixes it: serialisation moves into the base
PgQueryable.performIO, so any single-connection client is covered, while the pool stays parallel.fix: stabilize dev stack and silence pg transaction deprecation warning
chore: serialize in-transaction query fan-outs for the pg driver (#60)
fix(adapter-pg): serialize queries on single-connection clients
Fix audit findings: upload/save races, deletion race and pg transacti…