drizzle-team / drizzle-team/drizzle-orm
[BUG]: Transaction leaks a promise that never resolves or rejects
- Dominant language
- TypeScript
- Stars
- 35.8k
- Forks
- 1.6k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 4
Description
### Report hasn't been filed before.
- [x] I have verified that the bug I'm about to report hasn't been filed before.
### What version of `drizzle-orm` are you using?
0.44.4
### What version of `drizzle-kit` are you using?
0.31.1
### Other packages
drizzle-typebox@0.3.3
### Describe the Bug
I am using a postgres container version 17.4 using bun 1.2.19
I had a test that it always passed in **0.43.1** and now has become flaky; sometimes it passes and sometimes it doesn't.
When it doesn't pass it's because the test times out despite the error is being logged.
# The test
```ts
it('should create a location and throw ConflictError if the location code already exists', async () => {
await expect(createLocation({
name: 'testlocation',
companyId: company.id,
locationCode: 'OVD',
address: 'Some sort of address',
city: 'Madrid'
})).resolves.toBeDefined()
await expect(createLocation({
name: 'testlocation2',
companyId: company.id,
locationCode: 'OVD',
address: 'Another address',
city: 'Barcelona'
})).rejects.toThrow(ConflictError)
})
```
# The test output
```txt
✗ should create a location and throw ConflictError if the location code already exists [5001.29ms]
# Unhandled error between tests
-------------------------------
37 | name: 'testlocation2',
38 | companyId: company.id,
39 | locationCode: 'OVD',
40 | address: 'Another address',
41 | city: 'Barcelona'
42 | })).rejects.toThrow(ConflictError)
^
error: expect(received).toThrow(expected)
Expected constructor: ConflictError
Received constructor: Error
Received message: "terminating connection due to administrator command"
```
```ts
interface CreateLocationOptions {
companyId: string
name: string,
locationCode: string,
address: string
city: string
}
export async function createLocation(newLocation: CreateLocationOptions) {
const l = await db.transaction(async (tx) => {
try {
const [l] = await tx.insert(location).values(newLocation).returning()
await tx.insert(locationCounters).values({
locationId: l.id,
counter: 0
})
return l
} catch(err) {
// Yes I had to adapt this line to include the checks for DrizzleQueryError when upgrading to the latest version
if(err instanceof DrizzleQueryError && err.cause && "constraint" in err.cause && err.cause.constraint === 'unique_location_code') {
log.error('Unable to create location', { error: err, cname: err?.constructor?.name})
throw new ConflictError('El código de la ubicación ya existe')
}
throw err
}
})
log.debug(`Created location with ID ${l.id}`)
return l
}
```
And the logs:
```
debug: Created location with ID 3f2c53a4-d358-4673-bed9-d4c5eaa5037f {"file":"data/locations.ts","service":"issue-tracker-0","timestamp":"2025-08-03T15:20:53.031Z"}
error: Unable to create location {"cname":"DrizzleQueryError","error":{"cause":{"constraint":"unique_location_code","detail":"Key (location_code)=(OVD) already exists.","errno":"23505","schema":"public","table":"location"},"params":["a6918bee-2baa-43b5-9465-d343321e587c","testlocation2","OVD","Another address","Barcelona"],"query":"insert into \"location\" (\"id\", \"company_id\", \"name\", \"location_code\", \"address\", \"city\", \"created_at\", \"updated_at\") values (default, $1, $2, $3, $4, $5, default, default) returning \"id\", \"company_id\", \"name\", \"location_code\", \"address\", \"city\", \"created_at\", \"updated_at\""},"file":"data/locations.ts","service":"issue-tracker-0","timestamp":"2025-08-03T15:20:53.033Z"}
```
Contributor guide
Assessment
This issue has not been assessed yet.