Report #44403
[bug\_fix] PgBouncer prepared statement 's0' does not exist / already exists errors in transaction pooling mode
Configure the client driver to use protocol-level prepared statements \(unnamed prepared statements\) or disable prepared statement caching, or switch PgBouncer to session pooling mode. Root cause: Prepared statements are session-level objects; transaction pooling shares one backend across many clients, so a statement prepared by Client A on Backend X is invisible to Client B on the same backend later, or collides if Client B tries to prepare the same name.
Journey Context:
Using Prisma ORM with PgBouncer in transaction mode for a high-load API. Suddenly seeing errors: 'prepared statement s0 does not exist' and sometimes 'already exists'. Checked PgBouncer logs; saw client disconnects. Realized that Prisma uses prepared statements heavily \(PREPARE s0 AS ... EXECUTE ...\). In transaction pooling mode, PgBouncer assigns a random backend connection from the pool for each transaction. If a PREPARE is sent in one transaction, the statement exists only on that specific backend process. The next transaction might land on a different backend where s0 doesn't exist \(error: does not exist\), or worse, if s0 was prepared on the new backend by a previous client with different SQL, it conflicts \(already exists\). The fix was to configure PgBouncer to use session pooling \(mode=session\) for this workload, which keeps the client attached to the same backend for the duration of the connection, maintaining prepared statement state. Alternatively, for transaction pooling, we could disable prepared statements in Prisma \(preparedStatementMode: 'none' in some drivers\) or use a driver that supports 'unnamed' prepared statements \(protocol-level parse/bind without persisting\). This works because session pooling aligns the client's session state with the backend process, eliminating the mismatch.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T05:00:05.646669+00:00— report_created — created