sqlalchemy/alembic · error · ValueError

This MigrationScript instance has a multiple-entry list for

Error message

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

What it means

Raised by the MigrationScript.downgrade_ops property when more than one DowngradeOps entry exists in _downgrade_ops. Mirrors the upgrade case: once multiple downgrade streams exist, the scalar property is disabled and you must use downgrade_ops_list.

Source

Thrown at alembic/operations/ops.py:2856

        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`.

        .. seealso::

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

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

    @property

View on GitHub (pinned to 44fb345033)

Solutions

  1. Use script.downgrade_ops_list and iterate over all entries.
  2. Ensure only one DowngradeOps is stored if the scalar accessor is required.
  3. Branch rendering logic on len(downgrade_ops_list) > 1.

Example fix

// before
ops = script.downgrade_ops  # raises ValueError when multiple

// after
for ops in script.downgrade_ops_list:
    ...
Defensive patterns

Strategy: type-guard

Validate before calling

def get_downgrade_ops(script):
    n = len(script.downgrade_ops_list)
    if n > 1:
        return script.downgrade_ops_list
    return script.downgrade_ops_list[0] if n == 1 else None

Type guard

def has_multiple_downgrade_ops(script) -> bool:
    return len(script.downgrade_ops_list) > 1

Try / catch

try:
    ops = script.downgrade_ops
except ValueError:
    ops = script.downgrade_ops_list

Prevention

When it happens

Trigger: Accessing script.downgrade_ops on a MigrationScript populated with a list of multiple DowngradeOps; custom process_revision_directives that produce several downgrade passes corresponding to multiple upgrade passes.

Common situations: Custom autogenerate hooks splitting downgrades into multiple DowngradeOps; template/render code reading the scalar property on a multi-pass script.

Related errors


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