{"record":{"id":"5ecad8452431f4e4","repo":"sqlalchemy/alembic","slug":"constraint-cannot-be-produced-original-constraint","errorCode":null,"errorMessage":"constraint cannot be produced; original constraint is not present","messagePattern":"constraint cannot be produced; original constraint is not present","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"alembic/operations/ops.py","lineNumber":187,"sourceCode":"        return cls(\n            sqla_compat.constraint_name_or_none(constraint.name),\n            constraint_table.name,\n            schema=constraint_table.schema,\n            type_=types.get(constraint.__visit_name__),\n            _reverse=AddConstraintOp.from_constraint(constraint),\n        )\n\n    def to_constraint(self) -> Constraint:\n        if self._reverse is not None:\n            constraint = self._reverse.to_constraint()\n            constraint.name = self.constraint_name\n            constraint_table = sqla_compat._table_for_constraint(constraint)\n            constraint_table.name = self.table_name\n            constraint_table.schema = self.schema\n\n            return constraint\n        else:\n            raise ValueError(\n                \"constraint cannot be produced; \"\n                \"original constraint is not present\"\n            )\n\n    @classmethod\n    def drop_constraint(\n        cls,\n        operations: Operations,\n        constraint_name: str,\n        table_name: str,\n        type_: str | None = None,\n        *,\n        schema: str | None = None,\n        if_exists: bool | None = None,\n    ) -> None:\n        r\"\"\"Drop a constraint of the given name, typically via DROP CONSTRAINT.\n\n        :param constraint_name: name of the constraint.","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/5551b5d35f985c99cb8f1af2b3c526b050e4c059/alembic/operations/ops.py#L169-L205","documentation":"Raised as ValueError by DropConstraintOp.to_constraint() (ops.py:177-190) when the operation's _reverse attribute is None. The reverse reference is set only when DropConstraintOp is built via from_constraint(), which captures the original Constraint object so to_constraint() can reconstruct it. A manually constructed DropConstraintOp (no _reverse) cannot materialise a Constraint, so the call fails.","triggerScenarios":"Directly instantiating ops.DropConstraintOp(constraint_name='ck', table_name='t', type_='check') without passing _reverse, then calling .to_constraint() on it. This typically happens in custom operation code or when manipulating operation objects in autogenerate hooks rather than going through from_constraint().","commonSituations":"Third-party tooling or custom MigrateOperation subclasses that build DropConstraintOp by hand instead of using the from_constraint() classmethod. Also when calling op.drop_constraint(...) with only a name string (no constraint object), then introspecting the returned op.","solutions":["Build the op via the classmethod: DropConstraintOp.from_constraint(existing_constraint_obj), which sets _reverse automatically.","If you only have a name, construct the Constraint yourself with schema_obj.generic_constraint(name, table, type_) instead of calling to_constraint() on a bare op.","Avoid calling to_constraint() on ops created from a plain name; guard with `if op._reverse is not None:` before invoking."],"exampleFix":"// before\nop = ops.DropConstraintOp(constraint_name='ck', table_name='t', type_='check')\nconstraint = op.to_constraint()  # raises\n// after\nconstraint = operations.schema_obj.generic_constraint('ck', 't', 'check')\n# or, if you have the original:\nop = ops.DropConstraintOp.from_constraint(original_constraint)\nconstraint = op.to_constraint()","handlingStrategy":"validation","validationCode":"# Build DropConstraintOp via from_constraint so _reverse is populated.\nfrom alembic.operations.ops import DropConstraintOp\n\ndef safe_to_constraint(drop_op):\n    if drop_op._reverse is None:\n        raise ValueError(\n            'DropConstraintOp has no reverse; build via DropConstraintOp.from_constraint()'\n        )\n    return drop_op.to_constraint()\n\n# preferred construction:\ndrop_op = DropConstraintOp.from_constraint(original_constraint)\nconstraint = drop_op.to_constraint()","typeGuard":"from alembic.operations.ops import DropConstraintOp\n\ndef has_reverse(op: DropConstraintOp) -> bool:\n    return getattr(op, '_reverse', None) is not None","tryCatchPattern":null,"preventionTips":["Always construct DropConstraintOp with from_constraint() when you later need to_constraint().","For name-only drops, use schema_obj.generic_constraint() rather than to_constraint() on a bare op.","Guard custom loops with `if op._reverse is not None`."],"tags":["alembic","constraints","operations-api","database-migration"],"backgroundTag":null,"analyzedSha":"5551b5d35f985c99cb8f1af2b3c526b050e4c059","analyzedAt":"2026-08-11T01:38:46.612Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}