PostgreSQL / PgBouncer: Prepared statement "s0" already exists or does not exist
error: prepared statement "s0" already exists (or "unnamed prepared statement does not exist") with PgBouncer transaction pooling
Immediate Remediation
typescript
// In your database client URL or config, disable prepared statements for transaction pooler:
// For Prisma schema.prisma:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL") // pooled URL with ?pgbouncer=true
directUrl = env("DIRECT_URL") // unpooled URL (port 5432 without pooler)
}
// For node-postgres (pg) or Drizzle:
// Append ?statement_cache_size=0 or pass prepare: false to client poolRoot Cause Analysis
Transaction pooling mode in PgBouncer assigns subsequent queries to different backend connections, causing session-level named prepared statements to desynchronize.
Verification & Guardrails
- Always provide a directUrl for database migrations (e.g. prisma migrate dev) and a pooled url for runtime queries.
- In Prisma, append ?pgbouncer=true to the pooled connection string.
Have a custom or uncategorized crash?
Run your trace through our in-memory client privacy sandbox for instant SRE remediation.