sqlalchemy/alembic · error · TypeError
Can't send params and multiparams at the same time
Error message
Can't send params and multiparams at the same time
What it means
The internal _exec passes either params (a single dict for one row) or multiparams (a list of dicts for executemany). SQLAlchemy's connection.execute rejects passing both at once, so Alembic pre-empts that with a clear error. This indicates a caller that built both arguments simultaneously.
Source
Thrown at alembic/ddl/impl.py:245
else:
compile_kw = {}
if TYPE_CHECKING:
assert isinstance(construct, ClauseElement)
compiled = construct.compile(dialect=self.dialect, **compile_kw)
self.static_output(
str(compiled).replace("\t", " ").strip()
+ self.command_terminator
)
return None
else:
conn = self.connection
assert conn is not None
if execution_options:
conn = conn.execution_options(**execution_options)
if params and multiparams is not None:
raise TypeError(
"Can't send params and multiparams at the same time"
)
if multiparams:
return conn.execute(construct, multiparams)
else:
return conn.execute(construct, params)
def execute(
self,
sql: Executable | str,
execution_options: dict[str, Any] | None = None,
) -> None:
self._exec(sql, execution_options)
def alter_column(
self,
table_name: str,View on GitHub (pinned to 44fb345033)
Solutions
- Pass exactly one of params= or multiparams=. For multiple rows use multiparams=[{...},{...}].
- For a single row use params={'k': v} (or omit and pass the dict as the sole argument).
- If building dynamically, branch: if isinstance(rows, list) and rows and isinstance(rows[0], dict): use multiparams=rows else params=rows.
Example fix
// before
impl._exec(stmt, params={'a': 1}, multiparams=[{'a': 1}, {'a': 2}])
// after
impl._exec(stmt, multiparams=[{'a': 1}, {'a': 2}]) Defensive patterns
Strategy: validation
Validate before calling
def safe_exec(impl, construct, params=None, multiparams=None):
assert not (params and multiparams is not None), "Pass params OR multiparams, not both"
return impl._exec(construct, params=params or util.immutabledict(), multiparams=multiparams) Prevention
- Never pass both params= and multiparams= to _exec/execute.
- For multi-row inserts use multiparams=[dict, ...] only.
- Wrap lower-level _exec calls in a helper that enforces mutual exclusion.
When it happens
Trigger: A caller of impl._exec (internal API) or a custom Op that forwards both params=dict(...) and multiparams=[...] simultaneously; op.bulk_insert routes correctly into multiparams, so this surfaces via direct _exec use or custom operations.
Common situations: A custom op or migration that builds parameters dynamically and accidentally assigns both params and multiparams; mixing a single-row default with a multi-row list; calling impl._exec directly with both kwargs.
Related errors
- List expected
- List of dictionaries expected
- Dependency resolution failed; broken map
- Requested revision %s overlaps with other requested revision
AI-assisted analysis of sqlalchemy/alembic@44fb345033 (2026-08-04).
Data as JSON: /data/errors/82bd8acab32bea29.json.
Report an issue: GitHub.