typeorm/typeorm · error · TypeORMError

Spanner does not support exclusion constraints.

Error message

Spanner does not support exclusion constraints.

What it means

Thrown by SpannerQueryRunner.createExclusionConstraint. Spanner has no exclusion constraints (a Postgres-specific feature used for things like range-overlap prevention via GiST operators). Every method in the exclusion-constraint family throws unconditionally for spanner because the underlying engine cannot honor the request.

Source

Thrown at src/driver/spanner/SpannerQueryRunner.ts:1464

        ifExists?: boolean,
    ): Promise<void> {
        const promises = checkConstraints.map((checkConstraint) =>
            this.dropCheckConstraint(tableOrName, checkConstraint, ifExists),
        )
        await Promise.all(promises)
    }

    /**
     * Creates new exclusion constraint.
     *
     * @param tableOrName
     * @param exclusionConstraint
     */
    async createExclusionConstraint(
        tableOrName: Table | string,
        exclusionConstraint: TableExclusion,
    ): Promise<void> {
        throw new TypeORMError(
            `Spanner does not support exclusion constraints.`,
        )
    }

    /**
     * Creates new exclusion constraints.
     *
     * @param tableOrName
     * @param exclusionConstraints
     */
    async createExclusionConstraints(
        tableOrName: Table | string,
        exclusionConstraints: TableExclusion[],
    ): Promise<void> {
        throw new TypeORMError(
            `Spanner does not support exclusion constraints.`,
        )
    }

View on GitHub (pinned to 04ff4daedc)

Solutions

  1. Remove the exclusion constraint from the spanner migration path; it cannot be represented.
  2. Re-implement the exclusion business rule in application code or as a validating trigger/procedure spanner supports.
  3. Branch migrations per dialect: keep exclusion logic in a Postgres-only migration file gated by driver type.
  4. Search migrations with `rg -i "exclusion|ExclusionConstraint"` and delete/guard each hit before running on spanner.

Example fix

// before (migration copied from postgres)
await queryRunner.createExclusionConstraint('booking', new TableExclusion({
  name: 'exclude_overlap',
  expression: 'EXCLUDE USING gist (room_id WITH =, during WITH &&)',
}))

// after: drop it for spanner and enforce overlap checks in app code
if (dataSource.options.type !== 'spanner') {
  await queryRunner.createExclusionConstraint('booking', /* ... */)
}
Defensive patterns

Strategy: validation

Validate before calling

if (dataSource.options.type === 'spanner') {
  throw new Error('Exclusion constraints unsupported on spanner; skipping')
}

Type guard

function supportsExclusionConstraints(ds: DataSource): boolean {
  return ds.options.type === 'postgres'
}

Prevention

When it happens

Trigger: Calling queryRunner.createExclusionConstraint(table, exclusion) on spanner, or running a migration/synchronize that derives an exclusion change from an entity/metadata (rare, since TypeORM entity decorators don't expose exclusion directly, but raw migration code or copied Postgres migrations can).

Common situations: Reusing a Postgres migration (e.g. a booking-overlap exclusion) verbatim on a spanner target. Tooling that diffs schemas across DBs and emits exclusion statements generically.

Related errors


AI-assisted analysis of typeorm/typeorm@04ff4daedc (2026-08-03). Data as JSON: /data/errors/43cb985e5b213c52.json. Report an issue: GitHub.