The error, verbatim
Jump to the fix ↓DrizzleQueryError: Failed query: insert into "users" ("id", "email", "name") values (default, $1, $2)
params: a@b.c,A again
Tested on
- drizzle-orm
- 0.45.4 (latest), 0.44.0, 0.43.1
- drizzle-kit
- 0.31.11
- Database
- Postgres 17 (pg 8, postgres.js 3) and PGlite 0.5.8
- Node / OS
- 24.14.0 / Windows 11 Pro
✓ Re-verified on drizzle-orm 0.45.4 (Linux): 4/4 checks still hold · results
Contents
Failed query: is Drizzle telling you which SQL it sent, not what went wrong. Since drizzle-orm 0.44.0, every database error is wrapped in a DrizzleQueryError whose message is only the query and its parameters. The reason, the error from Postgres itself, is attached as cause. On 0.43.1 the same insert threw the Postgres error directly.
I reproduced five common causes on drizzle-orm 0.45.4. Every one produced the same kind of message, so the SQL alone doesn’t tell them apart.
Read the cause
The Postgres error, with its message and its code, is on e.cause:
try {
await db.insert(users).values({ email, name });
} catch (e) {
console.log(e.cause?.message, e.cause?.code);
}These are the five, with what the wrapper said and what e.cause said:
| What happened | Failed query: showed |
e.cause said |
Code |
|---|---|---|---|
| Table not created yet | select "id", "email", "name" from "users" |
relation "users" does not exist |
42P01 |
| Duplicate unique value | insert into "users" ... |
duplicate key value violates unique constraint "users_email_key" |
23505 |
| Missing required column | insert into "users" ..., params: x@y.z, |
null value in column "name" of relation "users" violates not-null constraint |
23502 |
| Foreign key points nowhere | insert into "posts" ..., params: 999,Hi |
insert or update on table "posts" violates foreign key constraint "posts_author_id_fkey" |
23503 |
| Wrong type in a filter | select ... where "posts"."id" = $1, params: not-a-uuid |
invalid input syntax for type uuid: "not-a-uuid" |
22P02 |
The params line can hint at it (an empty value after the last comma, 999 for an author ID), but only the cause says it outright.
Why you only see “Failed query”
The cause isn’t hidden from Node: console.error(e) prints it, further down after the stack trace, as cause: error: relation "nope" does not exist. It disappears wherever only the message is used: e.message, String(e), an error toast, a JSON response like { error: e.message }, or an error tracker that groups by message. All of those show the SQL and nothing else, which is why the same “Failed query” seems to have no explanation.
e.code === '23505' stopped working in 0.44
This is the breaking part of the change. A common way to turn a duplicate email into a friendly “that email is taken” message is to check the Postgres error code. I ran the same duplicate insert on three versions:
| drizzle-orm | Thrown | e.code |
e.cause.code |
|---|---|---|---|
| 0.43.1 | the Postgres error | 23505 |
— |
| 0.44.0 | DrizzleQueryError |
undefined |
23505 |
| 0.45.4 | DrizzleQueryError |
undefined |
23505 |
So after upgrading, a check on e.code is silently never true: no error, just the friendly message never shows, and the raw failure reaches the user instead.
Unwrap first, then check the code:
import { DrizzleQueryError } from 'drizzle-orm/errors';
const pgError = (e: unknown) => (e instanceof DrizzleQueryError ? e.cause : e) as { code?: string } | undefined;
try {
await db.insert(users).values({ email, name });
} catch (e) {
if (pgError(e)?.code === '23505') return { error: 'That email is already registered.' };
throw e;
}Import it from drizzle-orm/errors. On 0.45 it’s also exported from drizzle-orm itself, but on 0.44.0 importing it from there stops the app from loading. 0.43.1 has no drizzle-orm/errors at all, and doesn’t need it, since it throws the Postgres error directly.
The cause with node-postgres and postgres.js
Against a real Postgres 17 server, both popular drivers gave the same wrapper and the same e.cause.code, but the error inside differs, and one field name differs:
node-postgres (pg) |
postgres.js | |
|---|---|---|
e |
DrizzleQueryError |
DrizzleQueryError |
e.cause |
DatabaseError |
PostgresError |
e.cause.code |
23505 |
23505 |
e.cause.detail |
Key (email)=(a@b.c) already exists. |
same |
| Constraint name | e.cause.constraint |
e.cause.constraint_name |
detail is the most useful line for a duplicate: it names the column and the value. If you tell users which field is taken based on the constraint name, read the right property for your driver: constraint was undefined on postgres.js, and constraint_name was undefined on pg.
“applying migrations…” then Failed query: CREATE TABLE
The migration version of this error usually means the table already exists, created by drizzle-kit push or by hand, outside the migrations Drizzle keeps track of. I created users directly, then ran the generated migration through Drizzle’s migrate():
DrizzleQueryError: Failed query:
CREATE TABLE "users" (
"id" serial PRIMARY KEY NOT NULL,
"email" text NOT NULL,
...
cause: relation "users" already exists (code 42P07)
With the PGlite driver, drizzle-kit migrate itself printed nothing but its spinner and exited with code 1. Only running the migration from code showed the cause. If your migrate step fails silently, run it once through migrate() in a small script to see the error.
Don’t mix push and migrate on the same database. On a database that only ever received migrations, the same migration applied cleanly.
I didn’t test moving an existing pushed database onto migrations. In development, recreating the database and running the migrations from the start is the simple way out.
What didn’t work
How this was tested
drizzle-orm 0.45.4 (the latest), 0.44.0 and 0.43.1 with the PGlite 0.5.8 driver (Postgres compiled to WebAssembly), and 0.45.4 with node-postgres 8 and postgres.js 3 against a Postgres 17 server in Docker. Each case was a fresh in-memory database with a users table (unique email, required name) and a posts table with a foreign key to it. Migrations were generated with drizzle-kit 0.31.11 and applied with drizzle-kit migrate and with migrate() from drizzle-orm/pglite/migrator. Node 24.14.0 on Windows 11, October 10, 2026.
The code is public, so you can run it yourself: drizzle-failed-query in nk-repro.
— N.K., end of entry No.054