drizzle-team/drizzle-orm · error · DrizzleQueryError

Failed query: params

Error message

Failed query: ${queryString}
params: ${params}

What it means

PgPreparedQuery.queryWithCache (session.ts:70-74) wraps the underlying driver query in a try/catch for the no-cache path (cache is undefined, NoopCache, or queryMetadata is undefined). When the driver rejects — constraint violation, syntax error, type mismatch, connection drop, etc. — it is re-thrown as a DrizzleQueryError carrying the rendered SQL string and bound params, with the original error on .cause.

Solutions

  1. Read .cause on the DrizzleQueryError to get the original Postgres error code (e.g., 23505 unique_violation).
  2. Fix the offending data/constraint based on the Postgres SQLSTATE in the cause.
  3. For connection/timeout causes, tune pool size and statement timeouts.
  4. Log the queryString and params (redacted) from the error for debugging.

Example fix

// before
await db.insert(users).values({ email: 'dup@example.com' }); // 23505 unique_violation

// after
try {
  await db.insert(users).values({ email: 'dup@example.com' });
} catch (e) {
  if (e instanceof DrizzleQueryError && (e.cause as any)?.code === '23505') {
    // handle duplicate
  } else throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate inputs before sending to avoid common server rejections.
function assertInsertable(row: Record<string, unknown>, required: string[]) {
  for (const col of required) {
    if (row[col] === undefined || row[col] === null) {
      throw new Error(`Missing required column: ${col}`);
    }
  }
}

Type guard

import { DrizzleQueryError } from 'drizzle-orm';

function isPgError(e: unknown, code?: string): e is DrizzleQueryError {
  return e instanceof DrizzleQueryError
    && (code ? (e.cause as any)?.code === code : true);
}

Try / catch

import { DrizzleQueryError } from 'drizzle-orm';

try {
  await db.insert(users).values(row);
} catch (e) {
  if (e instanceof DrizzleQueryError) {
    const pg = e.cause as { code?: string; message?: string } | undefined;
    if (pg?.code === '23505') { /* unique violation */ }
    else if (pg?.code === '23503') { /* foreign key */ }
    else throw e;
  } else throw e;
}

Prevention

When it happens

Trigger: Any executed query that the Postgres server rejects: unique/foreign-key/check constraint violations, NOT NULL failures, undefined_column, invalid input syntax, division by zero, lock contention timeouts, or driver-level connection errors — occurring when caching is not configured.

Common situations: Inserting a duplicate key; violating a foreign key; passing a malformed value (e.g., bad date/UUID); connection pool exhausted mid-query; permission denied for role; transaction aborted by a prior statement.

Related errors


AI-assisted analysis of drizzle-team/drizzle-orm@b7862528fd (2026-08-03). Data as JSON: /api/errors/864d15d525c37f84. Report an issue: GitHub.

Appendix: source

Thrown at drizzle-orm/src/pg-core/session.ts:73

		return this;
	}

	static readonly [entityKind]: string = 'PgPreparedQuery';

	/** @internal */
	joinsNotNullableMap?: Record<string, boolean>;

	/** @internal */
	protected async queryWithCache<T>(
		queryString: string,
		params: any[],
		query: () => Promise<T>,
	): Promise<T> {
		if (this.cache === undefined || is(this.cache, NoopCache) || this.queryMetadata === undefined) {
			try {
				return await query();
			} catch (e) {
				throw new DrizzleQueryError(queryString, params, e as Error);
			}
		}

		// don't do any mutations, if globally is false
		if (this.cacheConfig && !this.cacheConfig.enable) {
			try {
				return await query();
			} catch (e) {
				throw new DrizzleQueryError(queryString, params, e as Error);
			}
		}

		// For mutate queries, we should query the database, wait for a response, and then perform invalidation
		if (
			(
				this.queryMetadata.type === 'insert' || this.queryMetadata.type === 'update'
				|| this.queryMetadata.type === 'delete'
			) && this.queryMetadata.tables.length > 0

View on GitHub (pinned to b7862528fd)