{"record":{"id":"b48faa1b6f493a97","repo":"sqlalchemy/alembic","slug":"sqlalchemy-2-0-required","errorCode":null,"errorMessage":"SQLAlchemy 2.0 required","messagePattern":"SQLAlchemy 2\\.0 required","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"alembic/operations/toimpl.py","lineNumber":233,"sourceCode":"\n\n@Operations.implementation_for(ops.AddConstraintOp)\ndef create_constraint(\n    operations: \"Operations\", operation: \"ops.AddConstraintOp\"\n) -> None:\n    operations.impl.add_constraint(\n        operation.to_constraint(operations.migration_context)\n    )\n\n\n@Operations.implementation_for(ops.DropConstraintOp)\ndef drop_constraint(\n    operations: \"Operations\", operation: \"ops.DropConstraintOp\"\n) -> None:\n    kw = {}\n    if operation.if_exists is not None:\n        if not sqla_2:\n            raise NotImplementedError(\"SQLAlchemy 2.0 required\")\n        kw[\"if_exists\"] = operation.if_exists\n    operations.impl.drop_constraint(\n        operations.schema_obj.generic_constraint(\n            operation.constraint_name,\n            operation.table_name,\n            operation.constraint_type,\n            schema=operation.schema,\n        ),\n        **kw,\n    )\n\n\n@Operations.implementation_for(ops.BulkInsertOp)\ndef bulk_insert(\n    operations: \"Operations\", operation: \"ops.BulkInsertOp\"\n) -> None:\n    operations.impl.bulk_insert(  # type: ignore[union-attr]\n        operation.table, operation.rows, multiinsert=operation.multiinsert","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/5551b5d35f985c99cb8f1af2b3c526b050e4c059/alembic/operations/toimpl.py#L215-L251","documentation":"Raised as NotImplementedError('SQLAlchemy 2.0 required') by the DropConstraintOp implementation (toimpl.py:226-233) when the operation's if_exists argument is set and the installed SQLAlchemy is older than 2.0. The `if_exists` kwarg for DROP CONSTRAINT relies on SQLAlchemy 2.0+ DDL features; sqla_2 (sqla_compat.py:69) gates it, so pre-2.0 installs cannot honour the flag.","triggerScenarios":"Calling op.drop_constraint('ck', 't', type_='check', if_exists=True) while running SQLAlchemy < 2.0 (e.g. 1.4.x). The implementation_for function checks `if operation.if_exists is not None and not sqla_2` and raises before touching the DB.","commonSituations":"Projects pinned to SQLAlchemy 1.4 (legacy apps) that pick up a newer Alembic migration using if_exists; CI with an older SQLAlchemy than local dev; dependency resolver installing an old SQLAlchemy.","solutions":["Upgrade SQLAlchemy to >= 2.0 (pip install 'SQLAlchemy>=2.0').","Remove the if_exists=True argument and handle existence yourself (e.g. query the catalog first), keeping SQLAlchemy 1.4.","Pin Alembic to a version compatible with your SQLAlchemy 1.4 install if upgrading SQLAlchemy is not possible."],"exampleFix":"// before (SQLAlchemy 1.4)\nop.drop_constraint('ck_t', 't', type_='check', if_exists=True)  # raises\n// after\nop.drop_constraint('ck_t', 't', type_='check')  # SQLAlchemy 1.4 compatible","handlingStrategy":"validation","validationCode":"# Check SQLAlchemy version before using if_exists on drop_constraint.\nimport sqlalchemy\nfrom alembic.util.sqla_compat import sqla_2\n\ndef drop_constraint_maybe(name, table, type_, if_exists=False):\n    if if_exists and not sqla_2:\n        raise RuntimeError(\n            f'drop_constraint(if_exists=True) needs SQLAlchemy>=2.0, got {sqlalchemy.__version__}'\n        )\n    op.drop_constraint(name, table, type_=type_, if_exists=if_exists if sqla_2 else None)","typeGuard":"from alembic.util.sqla_compat import sqla_2\n\ndef supports_drop_if_exists() -> bool:\n    return sqla_2","tryCatchPattern":null,"preventionTips":["Pin SQLAlchemy>=2.0 in requirements if you use if_exists.","Gate if_exists behind a version check in shared migration code.","Test migrations in CI against the minimum supported SQLAlchemy version."],"tags":["alembic","sqlalchemy-version","constraints","compatibility"],"backgroundTag":null,"analyzedSha":"5551b5d35f985c99cb8f1af2b3c526b050e4c059","analyzedAt":"2026-08-11T01:38:46.612Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}