knex/knex · error · Error

.dropUniqueIfExists() is not supported by redshift

Error message

.dropUniqueIfExists() is not supported by redshift

What it means

redshift-tablecompiler.js:34 throws because Redshift does not support IF EXISTS on DROP UNIQUE. The PG base class exposes dropUniqueIfExists, but Redshift's ALTER TABLE grammar lacks the optional-existence form, so the Redshift compiler overrides the method to reject the call.

Source

Thrown at lib/dialects/redshift/schema/redshift-tablecompiler.js:35

    );
  }

  dropIndex(columns, indexName) {
    this.client.logger.warn(
      'Redshift does not support the deletion of indexes.'
    );
  }

  dropPrimaryIfExists() {
    throw new Error('.dropPrimaryIfExists() is not supported by redshift');
  }

  dropForeignIfExists() {
    throw new Error('.dropForeignIfExists() is not supported by redshift');
  }

  dropUniqueIfExists() {
    throw new Error('.dropUniqueIfExists() is not supported by redshift');
  }

  // TODO: have to disable setting not null on columns that already exist...

  // Adds the "create" query to the query sequence.
  createQuery(columns, ifNot, like) {
    const createStatement = ifNot
      ? 'create table if not exists '
      : 'create table ';
    const columnsSql = ' (' + columns.sql.join(', ') + this._addChecks() + ')';
    let sql =
      createStatement +
      this.tableName() +
      (like && this.tableNameLike()
        ? ' (like ' + this.tableNameLike() + ')'
        : columnsSql);
    if (this.single.inherits)
      sql += ` like (${this.formatter.wrap(this.single.inherits)})`;

View on GitHub (pinned to e25d54bcb7)

Solutions

  1. Introspect pg_constraint/information_schema first and call table.dropUnique() only if it exists.
  2. Branch by dialect: Redshift -> dropUnique, PG -> dropUniqueIfExists.
  3. Wrap the drop in try/catch on Redshift when existence cannot be guaranteed.

Example fix

// before
schema.table('t', t => t.dropUniqueIfExists(['email'], 'u_t_email'));

// after (dialect branch)
schema.table('t', t => {
  if (knex.client.dialect === 'redshift') t.dropUnique(['email'], 'u_t_email');
  else t.dropUniqueIfExists(['email'], 'u_t_email');
});
Defensive patterns

Strategy: validation

Validate before calling

async function dropUniqueSafe(knex, table, name) {
  if (knex.client.dialect === 'redshift') {
    const c = await knex('information_schema.table_constraints')
      .where({ table_name: table, constraint_name: name, constraint_type: 'UNIQUE' }).first();
    if (c) await knex.schema.table(table, t => t.dropUnique([], name));
  } else {
    await knex.schema.table(table, t => t.dropUniqueIfExists([], name));
  }
}

Type guard

function isRedshiftDialect(client) {
  return /redshift/i.test((client && client.dialect) || '');
}

Try / catch

try {
  schema.table('t', t => t.dropUniqueIfExists(['email'], 'u_t_email'));
} catch (err) {
  if (/dropUniqueIfExists\(\) is not supported by redshift/i.test(err.message)) {
    schema.table('t', t => t.dropUnique(['email'], 'u_t_email'));
  } else throw err;
}

Prevention

When it happens

Trigger: Calling table.dropUniqueIfExists() in a migration against Redshift: schema.table('t', t => t.dropUniqueIfExists(['col'], 'u_t_col')). Also via any introspection-driven helper that prefers the IfExists form.

Common situations: Idempotent migration suites shared with Postgres; tools that always use the *IfExists variants; refactoring indexes on a Redshift warehouse using PG-oriented migration code.

Related errors


AI-assisted analysis of knex/knex@e25d54bcb7 (2026-08-03). Data as JSON: /data/errors/b7f22d9c06372299.json. Report an issue: GitHub.