n8n-io/n8n · error · TypeORMError

indexPredicate option is not supported by the current databa

Error message

indexPredicate option is not supported by the current database driver

What it means

In InsertQueryBuilder.createConflictExpression(), when onUpdate.conflict is a column array and onUpdate.indexPredicate is set, the code checks DriverUtils.isPostgresFamily(driver). Only Postgres-family drivers support a partial-index predicate (ON CONFLICT (col) WHERE predicate DO UPDATE). On any other driver the predicate is meaningless and TypeORMError is thrown at query build time.

Source

Thrown at packages/@n8n/typeorm/src/query-builder/InsertQueryBuilder.ts:400

		} else {
			query += ` DEFAULT VALUES`;
		}
		if (this.expressionMap.onUpdate?.upsertType !== 'primary-key') {
			if (this.connection.driver.supportedUpsertTypes.includes('on-conflict-do-update')) {
				if (this.expressionMap.onIgnore) {
					query += ' ON CONFLICT DO NOTHING ';
				} else if (this.expressionMap.onConflict) {
					query += ` ON CONFLICT ${this.expressionMap.onConflict} `;
				} else if (this.expressionMap.onUpdate) {
					const { overwrite, columns, conflict, skipUpdateIfNoValuesChanged, indexPredicate } =
						this.expressionMap.onUpdate;

					let conflictTarget = 'ON CONFLICT';

					if (Array.isArray(conflict)) {
						conflictTarget += ` ( ${conflict.map((column) => this.escape(column)).join(', ')} )`;
						if (indexPredicate && !DriverUtils.isPostgresFamily(this.connection.driver)) {
							throw new TypeORMError(
								`indexPredicate option is not supported by the current database driver`,
							);
						}
						if (indexPredicate && DriverUtils.isPostgresFamily(this.connection.driver)) {
							conflictTarget += ` WHERE ( ${indexPredicate} )`;
						}
					} else if (conflict) {
						conflictTarget += ` ON CONSTRAINT ${this.escape(conflict)}`;
					}

					const updatePart: string[] = [];

					if (Array.isArray(overwrite)) {
						updatePart.push(
							...overwrite.map(
								(column) => `${this.escape(column)} = EXCLUDED.${this.escape(column)}`,
							),
						);

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Remove indexPredicate from orUpdate options when targeting non-Postgres drivers.
  2. Branch on DriverUtils.isPostgresFamily(dataSource.driver) and only pass indexPredicate in the Postgres branch.
  3. Ensure the partial index actually exists in the Postgres schema before referencing its predicate.
  4. Use the 'primary-key' upsertType path or onConflict string if you need driver-portable behavior.

Example fix

// before
await dataSource.createQueryBuilder()
  .insert().into(User).values(payload)
  .orUpdate({
    conflict: ['email'],
    overwrite: ['name'],
    indexPredicate: 'deleted_at IS NULL', // throws on SQLite/MySQL
  }).execute();

// after
const isPg = DriverUtils.isPostgresFamily(dataSource.driver);
await dataSource.createQueryBuilder()
  .insert().into(User).values(payload)
  .orUpdate({
    conflict: ['email'],
    overwrite: ['name'],
    ...(isPg ? { indexPredicate: 'deleted_at IS NULL' } : {}),
  }).execute();
Defensive patterns

Strategy: validation

Validate before calling

import { DriverUtils } from '@n8n/typeorm/driver/DriverUtils';
function safeOrUpdateOptions(ds: DataSource, opts: { conflict: string[]; overwrite: string[]; indexPredicate?: string }) {
  const isPg = DriverUtils.isPostgresFamily(ds.driver);
  return { ...opts, ...(isPg && opts.indexPredicate ? { indexPredicate: opts.indexPredicate } : {}) };
}

Type guard

function isPostgresFamily(ds: DataSource): boolean {
  return DriverUtils.isPostgresFamily(ds.driver);
}

Prevention

When it happens

Trigger: Calling .orUpdate({ conflict: ['email'], overwrite: ['name'], indexPredicate: 'deleted_at IS NULL' }) on an upsert against SQLite, MySQL, CockroachDB-non-pg-path, or any non-Postgres driver. The conflict target is an array (column list) which is the branch that even evaluates indexPredicate.

Common situations: Developing upsert logic on Postgres locally then deploying to MySQL/SQLite. Using a partial unique index's predicate that only exists in Postgres. Copying a Postgres ON CONFLICT ... WHERE clause into a driver-portable code path.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/3c42b7507a69fd47. Report an issue: GitHub.