n8n-io/n8n · error · ReturningStatementNotSupportedError

OUTPUT or RETURNING clause only supported by Microsoft SQL S

Error message

OUTPUT or RETURNING clause only supported by Microsoft SQL Server or PostgreSQL or MariaDB databases.

What it means

DeleteQueryBuilder.returning() calls connection.driver.isReturningSqlSupported('delete') and throws ReturningStatementNotSupportedError when it returns false. RETURNING (Postgres) / OUTPUT (SQL Server) lets a DELETE return deleted columns, but drivers like older MySQL, Oracle, SAP HANA, and some SQLite configurations reject it. The guard runs at build configuration time, before any SQL is sent.

Source

Thrown at packages/@n8n/typeorm/src/query-builder/DeleteQueryBuilder.ts:237

	/**
	 * Optional returning/output clause.
	 * Returning is a SQL string containing returning statement.
	 */
	returning(returning: string): this;

	/**
	 * Optional returning/output clause.
	 */
	returning(returning: string | string[]): this;

	/**
	 * Optional returning/output clause.
	 */
	returning(returning: string | string[]): this {
		// not all databases support returning/output cause
		if (!this.connection.driver.isReturningSqlSupported('delete')) {
			throw new ReturningStatementNotSupportedError();
		}

		this.expressionMap.returning = returning;
		return this;
	}

	// -------------------------------------------------------------------------
	// Protected Methods
	// -------------------------------------------------------------------------

	/**
	 * Creates DELETE express used to perform query.
	 */
	protected createDeleteExpression() {
		const tableName = this.getTableName(this.getMainTableName());
		const whereExpression = this.createWhereExpression();
		const returningExpression = this.createReturningExpression('delete');

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Guard the .returning() call with a driver capability check: if (dataSource.driver.isReturningSqlSupported('delete')).
  2. Drop .returning() and issue a follow-up SELECT by id before delete, or capture affected ids another way.
  3. If you need DELETE ... RETURNING universally, use Postgres, SQL Server, or modern SQLite as the backing database.
  4. Factor driver-specific delete logic behind a repository strategy that branches on connection.options.type.

Example fix

// before
const res = await dataSource
  .createQueryBuilder().delete()
  .from(User).where('id = :id', { id })
  .returning(['id', 'email']).execute(); // throws on MySQL

// after
if (dataSource.driver.isReturningSqlSupported('delete')) {
  return dataSource.createQueryBuilder().delete().from(User)
    .where('id = :id', { id }).returning(['id', 'email']).execute();
}
const existing = await dataSource.getRepository(User).findOne({ where: { id } });
await dataSource.getRepository(User).delete(id);
return existing;
Defensive patterns

Strategy: validation

Validate before calling

function supportsDeleteReturning(ds: DataSource): boolean {
  return ds.driver.isReturningSqlSupported('delete');
}
if (!supportsDeleteReturning(dataSource)) { /* fall back to select-before-delete */ }

Type guard

function supportsReturning(driver: import('../driver/Driver').Driver, op: 'insert'|'update'|'delete'): boolean {
  return driver.isReturningSqlSupported(op);
}

Try / catch

try {
  return qb.delete().from(E).where(...).returning(cols).execute();
} catch (e) {
  if (e instanceof ReturningStatementNotSupportedError) { /* select-before-delete fallback */ }
  throw e;
}

Prevention

When it happens

Trigger: Calling .returning(['id']).delete().from(Entity).execute() (or delete().returning(...)) against a driver whose isReturningSqlSupported('delete') is false. Determined by the driver class: MssqlDriver and Postgres/AuroraPostgres return true; better-sqlite3 with 'enable-wal' may; MongoDriver, OracleDriver, MysqlDriver (pre-8 for some paths), SapDriver do not.

Common situations: Writing portable code against SQLite/MySQL in dev and Postgres in CI. Copying a Postgres RETURNING pattern into a feature that must run on MySQL/MariaDB. Forgetting that MongoDB driver is fundamentally non-relational.

Related errors


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