drizzle-team / drizzle-team/drizzle-orm

[BUG]: pushSchema fails on tables with composite primary keys — query params silently dropped

Open
#5,557 0 comments 1 reaction 0 assignees View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.