drizzle-team / drizzle-team/drizzle-orm
[BUG]: pushSchema fails on tables with composite primary keys — query params silently dropped
- Dominant language
- TypeScript
- Stars
- 35.8k
- Forks
- 1.6k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 4
Description
## What version of `drizzle-kit` are you using?
0.31.10 (also confirmed on 0.31.9)
## What version of `drizzle-orm` are you using?
0.45.2 (also confirmed on 0.45.1)
## Describe the Bug
`pushSchema` from `drizzle-kit/api` crashes with `there is no parameter $1` when the database contains a table with a composite primary key.
### Root cause
`pushSchema` creates an internal `db.query` wrapper that accepts `(query, params)` but silently discards `params`:
https://github.com/drizzle-team/drizzle-orm/blob/4aa6ecfee4b4728dadf6f77f071a149878a3c6c0/drizzle-kit/src/api.ts#L140
```typescript
const db: DB = {
query: async (query: string, params?: any[]) => {
const res = await drizzleInstance.execute(sql.raw(query));
// ^^^^^^^^^^^^^^
// params are never used
return res.rows;
},
};
```
The only caller that passes params is the composite primary key name lookup during PostgreSQL introspection:
https://github.com/drizzle-team/drizzle-orm/blob/4aa6ecfee4b4728dadf6f77f071a149878a3c6c0/drizzle-kit/src/serializer/pgSerializer.ts#L1409-L1420
```typescript
if (cprimaryKey.length > 1) {
const tableCompositePkName = await db.query(
`SELECT conname AS primary_key
FROM pg_constraint join pg_class on (pg_class.oid = conrelid)
WHERE contype = 'p'
AND connamespace = $1::regnamespace
AND pg_class.relname = $2;`,
[tableSchema, tableName] // <-- silently dropped by the wrapper
);
```
This code path is reached when a table has a multi-column primary key (`cprimaryKey.length > 1`). The `$1` and `$2` placeholders are sent to PostgreSQL without parameter values, causing:
```
error: there is no parameter $1
```
Tables with single-column primary keys skip this code path entirely and are unaffected.
### Additional issue: error is hidden by spinner
The error is also hidden from the user because drizzle-kit's internal `renderWithTask` spinner catches the error and calls `process.exit(1)`, so the caller never sees the actual failure reason — the process just exits silently.
### All three push functions are affected
The same `params`-dropping pattern exists in all three dialect push functions in `api.ts`:
- https://github.com/drizzle-team/drizzle-orm/blob/4aa6ecfee4b4728dadf6f77f071a149878a3c6c0/drizzle-kit/src/api.ts#L140
- https://github.com/drizzle-team/drizzle-orm/blob/4aa6ecfee4b4728dadf6f77f071a149878a3c6c0/drizzle-kit/src/api.ts#L279
- https://github.com/drizzle-team/drizzle-orm/blob/4aa6ecfee4b4728dadf6f77f071a149878a3c6c0/drizzle-kit/src/api.ts#L425
## Expected behavior
`pushSchema` should pass `params` through to the database query, and return `{ statementsToExecute: [] }` for a schema with no differences.
## Environment & Versions
- `drizzle-kit@0.31.10` (also `0.31.9`)
- `drizzle-orm@0.45.2` (also `0.45.1`)
- PostgreSQL 17
- Node.js v24
- Driver: `drizzle-orm/node-postgres`
## Reproduction
https://github.com/felamaslen/drizzle-push-bug
Contributor guide
Assessment
This issue has not been assessed yet.