typeorm/typeorm · error · TypeORMError
MySql does not support exclusion constraints.
Error message
MySql does not support exclusion constraints.
What it means
createExclusionConstraint() throws on MySQL because exclusion constraints are a PostgreSQL-specific feature (e.g., EXCLUDE USING GIST) with no MySQL equivalent. The method exists only to satisfy the shared QueryRunner interface.
Source
Thrown at src/driver/mysql/MysqlQueryRunner.ts:2225
async dropCheckConstraints(
tableOrName: Table | string,
checkConstraints: TableCheck[],
ifExists?: boolean,
): Promise<void> {
throw new TypeORMError(`MySql does not support check constraints.`)
}
/**
* Creates a new exclusion constraint.
*
* @param tableOrName
* @param exclusionConstraint
*/
async createExclusionConstraint(
tableOrName: Table | string,
exclusionConstraint: TableExclusion,
): Promise<void> {
throw new TypeORMError(`MySql does not support exclusion constraints.`)
}
/**
* Creates a new exclusion constraints.
*
* @param tableOrName
* @param exclusionConstraints
*/
async createExclusionConstraints(
tableOrName: Table | string,
exclusionConstraints: TableExclusion[],
): Promise<void> {
throw new TypeORMError(`MySql does not support exclusion constraints.`)
}
/**
* Drops exclusion constraint.
*View on GitHub (pinned to 04ff4daedc)
Solutions
- Enforce the exclusion rule with a trigger that checks for overlapping rows, or in the application layer with locking.
- Keep the constraint on Postgres only by branching on driver type.
- Use a generated column + unique index as a partial workaround for simple ranges.
Example fix
// before
await queryRunner.createExclusionConstraint('bookings', new TableExclusion({ name: 'no_overlap', expression: 'USING GIST (room_id WITH =, tstzrange(starts_at, ends_at) WITH &&)' }));
// after (MySQL trigger-based overlap guard)
await queryRunner.query(`CREATE TRIGGER no_overlap_ins BEFORE INSERT ON bookings FOR EACH ROW BEGIN IF EXISTS (SELECT 1 FROM bookings b WHERE b.room_id = NEW.room_id AND NEW.starts_at < b.ends_at AND b.starts_at < NEW.ends_at) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='overlapping booking'; END IF; END`); Defensive patterns
Strategy: validation
Validate before calling
import type { QueryRunner } from 'typeorm';
// Enforce an exclusion (e.g. no overlapping bookings) via a trigger:
async function createNoOverlap(runner: QueryRunner) {
await runner.query(`CREATE TRIGGER no_overlap_ins BEFORE INSERT ON bookings FOR EACH ROW BEGIN IF EXISTS (SELECT 1 FROM bookings b WHERE b.room_id = NEW.room_id AND NEW.starts_at < b.ends_at AND b.starts_at < NEW.ends_at) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='overlapping booking'; END IF; END`);
} Type guard
import { InstanceChecker } from 'typeorm';
const isTableExclusion = (v: unknown) => InstanceChecker.isTableExclusion(v); Try / catch
null
Prevention
- Treat exclusion constraints as Postgres-only; design MySQL equivalents as triggers or app-level locks.
- Document the driver-specific enforcement in the schema docs.
- Add concurrency tests for the overlap guard.
When it happens
Trigger: Calling queryRunner.createExclusionConstraint(table, exclusion) on MySQL; reusing Postgres exclusion logic (e.g., preventing overlapping time ranges) on a MySQL backend.
Common situations: Booking/scheduling apps that used EXCLUDE on Postgres being ported to MySQL; shared multi-DB schema code.
Related errors
- MySql does not support check constraints.
- MySql driver does not support table schemas
- Schema create queries are not supported by MySql driver.
- Schema drop queries are not supported by MySql driver.
- MySql does not support unique constraints. Use unique index
AI-assisted analysis of typeorm/typeorm@04ff4daedc (2026-08-03).
Data as JSON: /data/errors/3adbcb2269db79f5.json.
Report an issue: GitHub.