{"record":{"id":"ce917bf9b0935879","repo":"sqlalchemy/alembic","slug":"this-migrationscript-instance-has-a-multiple-entry","errorCode":null,"errorMessage":"This MigrationScript instance has a multiple-entry list for UpgradeOps; please use the upgrade_ops_list attribute.","messagePattern":"This MigrationScript instance has a multiple-entry list for UpgradeOps; please use the upgrade_ops_list attribute\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"alembic/operations/ops.py","lineNumber":2831,"sourceCode":"        self.splice = splice\n        self.branch_label = branch_label\n        self.version_path = (\n            pathlib.Path(version_path).as_posix() if version_path else None\n        )\n        self.depends_on = depends_on\n        self.upgrade_ops = upgrade_ops\n        self.downgrade_ops = downgrade_ops\n\n    @property\n    def upgrade_ops(self) -> UpgradeOps | None:\n        \"\"\"An instance of :class:`.UpgradeOps`.\n\n        .. seealso::\n\n            :attr:`.MigrationScript.upgrade_ops_list`\n        \"\"\"\n        if len(self._upgrade_ops) > 1:\n            raise ValueError(\n                \"This MigrationScript instance has a multiple-entry \"\n                \"list for UpgradeOps; please use the \"\n                \"upgrade_ops_list attribute.\"\n            )\n        elif not self._upgrade_ops:\n            return None\n        else:\n            return self._upgrade_ops[0]\n\n    @upgrade_ops.setter\n    def upgrade_ops(self, upgrade_ops: UpgradeOps | list[UpgradeOps]) -> None:\n        self._upgrade_ops = util.to_list(upgrade_ops)\n        for elem in self._upgrade_ops:\n            assert isinstance(elem, UpgradeOps)\n\n    @property\n    def downgrade_ops(self) -> DowngradeOps | None:\n        \"\"\"An instance of :class:`.DowngradeOps`.","sourceCodeStart":2813,"sourceCodeEnd":2849,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/5551b5d35f985c99cb8f1af2b3c526b050e4c059/alembic/operations/ops.py#L2813-L2849","documentation":"Raised as ValueError by the MigrationScript.upgrade_ops getter (ops.py:2822-2835) when self._upgrade_ops contains more than one entry. A MigrationScript normally holds a single UpgradeOps; but in a multi-database ('multidb') autogenerate setup multiple UpgradeOps (one per database) are stored, and the singular accessor is disabled on purpose, directing callers to the upgrade_ops_list attribute.","triggerScenarios":"Accessing migration_script.upgrade_ops on a script produced by a multi-database (multidb) env.py / template where configure() was called per-DB, yielding a list of >1 UpgradeOps. Common in `alembic revision --autogenerate` against multiple engines.","commonSituations":"Switching a project from single-DB to the multidb template, or writing custom autogenerate hooks (e.g. in a `process_revision_directives` function) that assume a single UpgradeOps but receive a list.","solutions":["Use migration_script.upgrade_ops_list, which always returns a list (single- or multi-entry), and iterate it.","In custom hooks, pick the right entry: `for uo in script.upgrade_ops_list: ...` rather than `script.upgrade_ops`.","If you truly expect a single DB, ensure your env.py does not register multiple UpgradeOps."],"exampleFix":"// before\ndef process_revision_directives(context, revision, directives):\n    script = directives[0]\n    up = script.upgrade_ops  # raises in multidb\n// after\ndef process_revision_directives(context, revision, directives):\n    script = directives[0]\n    for up in script.upgrade_ops_list:\n        up.ops.append(my_custom_op)","handlingStrategy":"validation","validationCode":"# In process_revision_directives, always iterate the list form.\ndef process_revision_directives(context, revision, directives):\n    script = directives[0]\n    for up_ops in script.upgrade_ops_list:  # never script.upgrade_ops\n        up_ops.ops.extend(my_extra_ops)","typeGuard":"from alembic.operations.ops import MigrationScript\n\ndef is_multidb(script: MigrationScript) -> bool:\n    return len(script._upgrade_ops) > 1","tryCatchPattern":"try:\n    up = script.upgrade_ops\nexcept ValueError:\n    up = None\nops_list = script.upgrade_ops_list  # always safe","preventionTips":["Prefer script.upgrade_ops_list over script.upgrade_ops in any generic/custom code.","Detect multidb by len(script._upgrade_ops) > 1 before touching the singular accessor.","Write process_revision_directives hooks to iterate the list, not assume one entry."],"tags":["alembic","autogenerate","multidb","operations-api"],"backgroundTag":null,"analyzedSha":"5551b5d35f985c99cb8f1af2b3c526b050e4c059","analyzedAt":"2026-08-11T01:38:46.612Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}