{"record":{"id":"82bd8acab32bea29","repo":"sqlalchemy/alembic","slug":"can-t-send-params-and-multiparams-at-the-same-time","errorCode":null,"errorMessage":"Can't send params and multiparams at the same time","messagePattern":"Can't send params and multiparams at the same time","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"alembic/ddl/impl.py","lineNumber":245,"sourceCode":"            else:\n                compile_kw = {}\n\n            if TYPE_CHECKING:\n                assert isinstance(construct, ClauseElement)\n            compiled = construct.compile(dialect=self.dialect, **compile_kw)\n            self.static_output(\n                str(compiled).replace(\"\\t\", \"    \").strip()\n                + self.command_terminator\n            )\n            return None\n        else:\n            conn = self.connection\n            assert conn is not None\n            if execution_options:\n                conn = conn.execution_options(**execution_options)\n\n            if params and multiparams is not None:\n                raise TypeError(\n                    \"Can't send params and multiparams at the same time\"\n                )\n\n            if multiparams:\n                return conn.execute(construct, multiparams)\n            else:\n                return conn.execute(construct, params)\n\n    def execute(\n        self,\n        sql: Executable | str,\n        execution_options: dict[str, Any] | None = None,\n    ) -> None:\n        self._exec(sql, execution_options)\n\n    def alter_column(\n        self,\n        table_name: str,","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/5551b5d35f985c99cb8f1af2b3c526b050e4c059/alembic/ddl/impl.py#L227-L263","documentation":"DefaultImpl._exec raises TypeError when both params (a single parameter dict) and multiparams (a list of parameter dicts) are passed simultaneously to the same execution call. SQLAlchemy's execute() accepts one form or the other, not both, so Alembic rejects the combination early.","triggerScenarios":"Calling impl._exec(construct, params={...}, multiparams=[...]) directly, or higher-level code that forwards both to conn.execute. Typically arises inside custom impl subclasses or patched execution helpers.","commonSituations":"Custom DefaultImpl subclasses overriding _exec and forwarding both; code that naively merges single-row and multi-row execution into one call.","solutions":["Pass only one parameter style: use params for a single row, or multiparams for multiple rows.","If you have a single row, put it in multiparams=[row] and omit params.","Audit custom impl overrides of _exec to ensure they never forward both arguments."],"exampleFix":"# before\nimpl._exec(stmt, params={'a': 1}, multiparams=[{'a': 1}, {'a': 2}])\n\n# after\nimpl._exec(stmt, multiparams=[{'a': 1}, {'a': 2}])","handlingStrategy":"validation","validationCode":"def call_exec(impl, construct, params=None, multiparams=None):\n    if params and multiparams is not None:\n        raise ValueError('Pass params XOR multiparams, not both')\n    impl._exec(construct, params=params or {}, multiparams=multiparams)","typeGuard":"def has_single_param_style(params, multiparams) -> bool:\n    return not (params and multiparams is not None)","tryCatchPattern":null,"preventionTips":["Never forward both params and multiparams to _exec; choose one.","For multi-row inserts, use multiparams=[row1, row2] and leave params empty.","Audit custom DefaultImpl overrides of _exec for this contract."],"tags":["ddl","execution","sql-params","impl"],"backgroundTag":null,"analyzedSha":"5551b5d35f985c99cb8f1af2b3c526b050e4c059","analyzedAt":"2026-08-11T01:38:46.612Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}