{"id":"43cb985e5b213c52","repo":"typeorm/typeorm","slug":"spanner-does-not-support-exclusion-constraints","errorCode":null,"errorMessage":"Spanner does not support exclusion constraints.","messagePattern":"Spanner does not support exclusion constraints\\.","errorType":"exception","errorClass":"TypeORMError","httpStatus":null,"severity":"error","filePath":"src/driver/spanner/SpannerQueryRunner.ts","lineNumber":1464,"sourceCode":"        ifExists?: boolean,\n    ): Promise<void> {\n        const promises = checkConstraints.map((checkConstraint) =>\n            this.dropCheckConstraint(tableOrName, checkConstraint, ifExists),\n        )\n        await Promise.all(promises)\n    }\n\n    /**\n     * Creates new exclusion constraint.\n     *\n     * @param tableOrName\n     * @param exclusionConstraint\n     */\n    async createExclusionConstraint(\n        tableOrName: Table | string,\n        exclusionConstraint: TableExclusion,\n    ): Promise<void> {\n        throw new TypeORMError(\n            `Spanner does not support exclusion constraints.`,\n        )\n    }\n\n    /**\n     * Creates new exclusion constraints.\n     *\n     * @param tableOrName\n     * @param exclusionConstraints\n     */\n    async createExclusionConstraints(\n        tableOrName: Table | string,\n        exclusionConstraints: TableExclusion[],\n    ): Promise<void> {\n        throw new TypeORMError(\n            `Spanner does not support exclusion constraints.`,\n        )\n    }","sourceCodeStart":1446,"sourceCodeEnd":1482,"githubUrl":"https://github.com/typeorm/typeorm/blob/04ff4daedcf60fa4ffd0d5d33bbafaac1a9bbc96/src/driver/spanner/SpannerQueryRunner.ts#L1446-L1482","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Remove the exclusion constraint from the spanner migration path; it cannot be represented.","Re-implement the exclusion business rule in application code or as a validating trigger/procedure spanner supports.","Branch migrations per dialect: keep exclusion logic in a Postgres-only migration file gated by driver type.","Search migrations with `rg -i \"exclusion|ExclusionConstraint\"` and delete/guard each hit before running on spanner."],"exampleFix":"// before (migration copied from postgres)\nawait queryRunner.createExclusionConstraint('booking', new TableExclusion({\n  name: 'exclude_overlap',\n  expression: 'EXCLUDE USING gist (room_id WITH =, during WITH &&)',\n}))\n\n// after: drop it for spanner and enforce overlap checks in app code\nif (dataSource.options.type !== 'spanner') {\n  await queryRunner.createExclusionConstraint('booking', /* ... */)\n}","handlingStrategy":"validation","validationCode":"if (dataSource.options.type === 'spanner') {\n  throw new Error('Exclusion constraints unsupported on spanner; skipping')\n}","typeGuard":"function supportsExclusionConstraints(ds: DataSource): boolean {\n  return ds.options.type === 'postgres'\n}","tryCatchPattern":null,"preventionTips":["Branch migration logic by dialect and only create exclusion constraints on postgres.","Document range-overlap rules in app code for spanner targets.","Lint migrations for TableExclusion usage before running on spanner."],"tags":["spanner","schema","exclusion-constraint","unsupported-feature"],"analyzedSha":"04ff4daedcf60fa4ffd0d5d33bbafaac1a9bbc96","analyzedAt":"2026-08-03T18:27:32.281Z","schemaVersion":2}