{"id":"e3583ab12f6364ee","repo":"knex/knex","slug":"mssql-cannot-create-constraint-with-predicate","errorCode":null,"errorMessage":"mssql cannot create constraint with predicate","messagePattern":"mssql cannot create constraint with predicate","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/dialects/mssql/schema/mssql-tablecompiler.js","lineNumber":299,"sourceCode":"   *\n   * @param {string | string[]} columns\n   * @param {string | {indexName: undefined | string, deferrable?: 'not deferrable'|'deferred'|'immediate', useConstraint?: true|false, predicate?: QueryBuilder }} indexName\n   */\n  unique(columns, indexName) {\n    /** @type {string | undefined} */\n    let deferrable;\n    let useConstraint = false;\n    let predicate;\n    if (isObject(indexName)) {\n      ({ indexName, deferrable, useConstraint, predicate } = indexName);\n    }\n    if (deferrable && deferrable !== 'not deferrable') {\n      this.client.logger.warn(\n        `mssql: unique index [${indexName}] will not be deferrable ${deferrable} because mssql does not support deferred constraints.`\n      );\n    }\n    if (useConstraint && predicate) {\n      throw new Error('mssql cannot create constraint with predicate');\n    }\n    indexName = indexName\n      ? this.formatter.wrap(indexName)\n      : this._indexCommand('unique', this.tableNameRaw, columns);\n\n    if (!Array.isArray(columns)) {\n      columns = [columns];\n    }\n\n    if (useConstraint) {\n      // mssql supports unique indexes and unique constraints.\n      // unique indexes cannot be used with foreign key relationships hence unique constraints are used instead.\n      this.pushQuery(\n        `ALTER TABLE ${this.tableName()} ADD CONSTRAINT ${indexName} UNIQUE (${this.formatter.columnize(\n          columns\n        )})`\n      );\n    } else {","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/knex/knex/blob/e25d54bcb707714a17f5a5744eba5c4246bb4d1d/lib/dialects/mssql/schema/mssql-tablecompiler.js#L281-L317","documentation":"mssql's `unique()` in the table compiler throws when you request BOTH `useConstraint: true` AND a `predicate` in the options object. SQL Server unique constraints cannot carry a `WHERE` predicate (only filtered unique *indexes* can), so Knex rejects the contradictory combination at compile time.","triggerScenarios":"Calling `.unique('col', { useConstraint: true, predicate: knex.raw('...') })` or the option-object form `{ indexName, useConstraint: true, predicate: ... }`; migrating a postgres partial unique constraint to mssql verbatim.","commonSituations":"Partial unique constraints (e.g. 'unique email where active = 1') ported from postgres to SQL Server; generic migration generators that always set `useConstraint` plus a predicate; conditional uniqueness needed for soft-delete patterns.","solutions":["For a filtered/partial unique rule on mssql, use a unique *index* with a WHERE filter: drop `useConstraint` and keep `predicate` (Knex emits `CREATE UNIQUE INDEX ... WHERE ...`).","If you specifically need a constraint (e.g. for FK relationships), remove the `predicate` — constraints cannot be filtered on SQL Server.","Express soft-delete uniqueness via a computed column (e.g. a `NULL`-able filtered unique index on a computed expression).","Branch migration DDL by dialect for partial-unique rules."],"exampleFix":"// before\nknex.schema.alterTable('users', t => t.unique('email', { useConstraint: true, predicate: knex.raw('WHERE deleted_at IS NULL') }));\n// after (filtered unique index, not a constraint)\nknex.schema.alterTable('users', t => t.unique('email', { indexName: 'uq_users_email_active', predicate: knex.raw('WHERE deleted_at IS NULL') }));","handlingStrategy":"validation","validationCode":"function buildUnique(t, columns, opts = {}) {\n  if (opts.useConstraint && opts.predicate) {\n    throw new Error('mssql cannot create a constraint with a predicate; use a unique index instead');\n  }\n  return t.unique(columns, opts);\n}","typeGuard":"function isValidMssqlUniqueOptions(o) { return !(o && o.useConstraint && o.predicate); }","tryCatchPattern":null,"preventionTips":["For partial uniqueness on mssql, use a unique index (omit useConstraint), not a constraint.","Drop the predicate when useConstraint is required.","Branch unique DDL by dialect in migrations."],"tags":["schema","mssql","constraint","unique-index","dialect"],"analyzedSha":"e25d54bcb707714a17f5a5744eba5c4246bb4d1d","analyzedAt":"2026-08-03T18:35:32.148Z","schemaVersion":2}