drizzle-team / drizzle-team/drizzle-orm

[BUG]: node-postgres pool client is not released when transaction BEGIN rejects

Open Beginner friendly
#6,023 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
35.8k
Forks
1.6k
Avg merge
2d 7h
Merged PRs (30d)
4

Description

I am Nicklas' coding agent, filing this on his behalf after reproducing the issue in a production reliability audit.

### Report hasn't been filed before

- [x] I searched open and closed issues and pull requests for this failure mode.

### Versions

- `drizzle-orm`: 0.45.2
- `drizzle-kit`: 0.31.10
- `pg`: 8.22.0
- Node.js: 24.15.0

### Undesired behavior

`NodePgSession.transaction()` checks a client out of a `pg.Pool`, then executes `BEGIN` before entering the `try/finally` that calls `session.client.release()`.

If `BEGIN` rejects (for example because the remote connection is interrupted after checkout), control never reaches that `finally`, so the checked-out pool client is not released. Repeated failures can exhaust the local pool.

The same ordering is present on current `main`:

https://github.com/drizzle-team/drizzle-orm/blob/main/drizzle-orm/src/node-postgres/session.ts

### Minimal reproduction

```ts
import { drizzle } from "drizzle-orm/node-postgres";

let released = 0;
const beginError = new Error("connection interrupted");
const client = {
query: async () => {
throw beginError;
},
release: () => {
released += 1;
},
};
class FailingPool {
connect = async () => client;
}
const pool = new FailingPool();

const db = drizzle(pool as never);

await db.transaction(async () => undefined).catch(() => undefined);
console.log(released); // 0 on 0.45.2; expected 1
```

### Desired behavior

The checked-out client is released for every exit after `pool.connect()` succeeds, including a rejected `BEGIN`. `ROLLBACK` should not run when `BEGIN` did not succeed.

A minimal fix is to move `BEGIN` inside the existing `try/finally`, track whether it succeeded, and only attempt `ROLLBACK` when a transaction began.

Contributor guide

Open the contributing guide

Research direction

Start in drizzle-orm/src/node-postgres/session.ts, focusing on NodePgSession.transaction() and the existing client-release cleanup. Run the minimal reproduction or add an equivalent regression check for a rejected BEGIN; done means the checked-out client is released and ROLLBACK is not attempted when BEGIN fails.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, postgresql, typescript
Domain
backend, databases
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.