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
- Switch to script.upgrade_ops_list and iterate over all entries instead of script.upgrade_ops.
- If you only need the single-entry case, ensure exactly one UpgradeOps is stored before accessing the scalar property.
- 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
- Prefer the upgrade_ops_list accessor in generic/render code.
- Branch on len(upgrade_ops_list) in process_revision_directives hooks.
- Document that scalar access is single-entry only.
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
- This MigrationScript instance has a multiple-entry list for
- constraint cannot be produced; original constraint is not pr
- operation is not reversible; original column is not present
- 'type' can be one of %s
- Can't drop table in batch mode
AI-assisted analysis of sqlalchemy/alembic@44fb345033 (2026-08-04).
Data as JSON: /data/errors/ce917bf9b0935879.json.
Report an issue: GitHub.