sqlalchemy/alembic · error · ValueError

This MigrationScript instance has a multiple-entry list for

Error message

This MigrationScript instance has a multiple-entry list for UpgradeOps; please use the upgrade_ops_list attribute.

What it means

Raised by the MigrationScript.upgrade_ops property when more than one UpgradeOps entry exists in the internal _upgrade_ops list. The scalar property can only return a single entry; once multiple upgrade op streams exist (multi-pass autogenerate, process_revision_directives producing several UpgradeOps) you must read upgrade_ops_list instead.

Source

Thrown at alembic/operations/ops.py:2831

        self.splice = splice
        self.branch_label = branch_label
        self.version_path = (
            pathlib.Path(version_path).as_posix() if version_path else None
        )
        self.depends_on = depends_on
        self.upgrade_ops = upgrade_ops
        self.downgrade_ops = downgrade_ops

    @property
    def upgrade_ops(self) -> UpgradeOps | None:
        """An instance of :class:`.UpgradeOps`.

        .. seealso::

            :attr:`.MigrationScript.upgrade_ops_list`
        """
        if len(self._upgrade_ops) > 1:
            raise ValueError(
                "This MigrationScript instance has a multiple-entry "
                "list for UpgradeOps; please use the "
                "upgrade_ops_list attribute."
            )
        elif not self._upgrade_ops:
            return None
        else:
            return self._upgrade_ops[0]

    @upgrade_ops.setter
    def upgrade_ops(self, upgrade_ops: UpgradeOps | list[UpgradeOps]) -> None:
        self._upgrade_ops = util.to_list(upgrade_ops)
        for elem in self._upgrade_ops:
            assert isinstance(elem, UpgradeOps)

    @property
    def downgrade_ops(self) -> DowngradeOps | None:
        """An instance of :class:`.DowngradeOps`.

View on GitHub (pinned to 44fb345033)

Solutions

  1. Switch to script.upgrade_ops_list and iterate over all entries instead of script.upgrade_ops.
  2. If you only need the single-entry case, ensure exactly one UpgradeOps is stored before accessing the scalar property.
  3. In rendering/process_revision_directives code, branch on len(upgrade_ops_list) > 1 and use the list form.

Example fix

// before
script = scripts[0]
ops = script.upgrade_ops  # raises ValueError when multiple

// after
script = scripts[0]
for ops in script.upgrade_ops_list:
    ...
Defensive patterns

Strategy: type-guard

Validate before calling

def get_upgrade_ops(script):
    n = len(script.upgrade_ops_list)
    if n > 1:
        return script.upgrade_ops_list  # multi-entry
    return script.upgrade_ops_list[0] if n == 1 else None

Type guard

def has_multiple_upgrade_ops(script) -> bool:
    return len(script.upgrade_ops_list) > 1

Try / catch

try:
    ops = script.upgrade_ops
except ValueError:
    ops = script.upgrade_ops_list

Prevention

When it happens

Trigger: Accessing script.upgrade_ops on a MigrationScript whose __init__ was passed a list of multiple UpgradeOps, or whose setter received a list; typically inside custom process_revision_directives hooks that append multiple UpgradeOps, or when rendering a revision that performs several independent upgrade passes.

Common situations: Custom autogenerate process_revision_directives that splits work into multiple UpgradeOps; iterating autogenerated scripts and accessing the scalar property instead of the list property.

Related errors


AI-assisted analysis of sqlalchemy/alembic@44fb345033 (2026-08-04). Data as JSON: /data/errors/ce917bf9b0935879.json. Report an issue: GitHub.