drizzle-team / drizzle-team/drizzle-orm
[BUG]: drizzle-kit push swallows every execution error and exits 0, silently skipping the remaining statements
- Dominant language
- TypeScript
- Stars
- 35.8k
- Forks
- 1.6k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 4
Description
### What version of `drizzle-orm` are you using?
0.45.2
### What version of `drizzle-kit` are you using?
0.31.10
### Describe the Bug
`drizzle-kit push` wraps its entire statement-execution loop in a `catch` that only logs, so **a failed push prints an error and then exits 0**, and every statement after the failing one is never attempted.
`src/cli/commands/push.ts`, `pgPush` (0.31.10, `bin.cjs` around the `pgPush = async (...)` definition):
```js
try {
if (statements.sqlStatements.length === 0) {
render(`[i] No changes detected`)
} else {
// …pgSuggestions, prompts…
for (const dStmnt of statementsToExecute) {
await db.query(dStmnt) // <-- throws here
}
render(`[✓] Changes applied`)
}
} catch (e) {
console.error(e) // <-- logged, then the function returns normally
}
```
There is no re-throw and no `process.exit(1)`, so the CLI's exit status is 0.
Two consequences, and the second is the damaging one:
1. **The exit status is not consultable.** `drizzle-kit push && next-thing` runs `next-thing` after a push that applied nothing. Any CI step, `package.json` chain, or script that gates on push's status is gated on a value that is always 0.
2. **Partial application is reported as success.** `statementsToExecute` is executed in order inside the `try`. When statement *N* throws, statements *N+1 …* are skipped — silently. In our case the failing statement sorts before the `CREATE CHECK CONSTRAINT` group, so five CHECK constraints we had just added to the schema were never applied to the database, while the command reported success and the chain continued.
The same `catch` is not present in `sqlitePush` / `libSQLPush` in the same file, so this looks like an oversight rather than a deliberate policy.
### Expected behavior
`drizzle-kit push` exits non-zero when any statement fails, so `push && …` is a real gate.
If aborting on the first failure is not wanted, the alternative that still fixes the reporting is to run the remaining statements, collect the failures, print them, and exit non-zero — what must not happen is "some statements did not run" being reported with the same exit status as "everything applied".
### Environment & setup
Node 26.4.0, PGlite 0.5.4 (`driver: "pglite"`), macOS/Linux. The statement that fails in our case is a separate defect (composite-PK churn emitting a two-command statement) filed separately — but any failing statement reproduces this one:
```ts
// drizzle.config.ts
export default defineConfig({
dialect: "postgresql",
driver: "pglite",
schema: "./schema.ts",
dbCredentials: { url: ".data/pglite" },
})
```
```console
$ npx drizzle-kit push --force; echo "exit=$?"
[✓] Pulling schema from database...
error: cannot insert multiple commands into a prepared statement
…
exit=0
```
Contributor guide
Research direction
Start in src/cli/commands/push.ts at pgPush and inspect its statement-execution try/catch, comparing it with sqlitePush and libSQLPush. Reproduce the behavior with npx drizzle-kit push --force and verify that a failed statement produces a non-zero exit status instead of silently skipping later statements and reporting success.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- nodejs, postgresql, typescript
- Domain
- cli, databases
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 82/100