{"id":"8ca4fd3f95e516e0","repo":"sqlalchemy/sqlalchemy","slug":"params-is-not-supported-for-insert-update-delete","errorCode":null,"errorMessage":"params() is not supported for INSERT/UPDATE/DELETE statements. To set the values for an INSERT or UPDATE statement, use stmt.values(**parameters).","messagePattern":"params\\(\\) is not supported for INSERT/UPDATE/DELETE statements\\. To set the values for an INSERT or UPDATE statement, use stmt\\.values\\(\\*\\*parameters\\)\\.","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"lib/sqlalchemy/sql/dml.py","lineNumber":477,"sourceCode":"                proxy_key,\n                fallback_label_name,\n                c,\n                repeated,\n            ) in (self._generate_columns_plus_names(False))\n            if is_column_element(c)\n        ]\n\n        columns._populate_separate_keys(prox)\n\n    def params(self, *arg: Any, **kw: Any) -> NoReturn:\n        \"\"\"Set the parameters for the statement.\n\n        This method raises ``NotImplementedError`` on the base class,\n        and is overridden by :class:`.ValuesBase` to provide the\n        SET/VALUES clause of UPDATE and INSERT.\n\n        \"\"\"\n        raise NotImplementedError(\n            \"params() is not supported for INSERT/UPDATE/DELETE statements.\"\n            \" To set the values for an INSERT or UPDATE statement, use\"\n            \" stmt.values(**parameters).\"\n        )\n\n    @_generative\n    def with_dialect_options(self, **opt: Any) -> Self:\n        \"\"\"Add dialect options to this INSERT/UPDATE/DELETE object.\n\n        e.g.::\n\n            upd = table.update().dialect_options(mysql_limit=10)\n\n        .. versionadded:: 1.4 - this method supersedes the dialect options\n           associated with the constructor.\n\n\n        \"\"\"","sourceCodeStart":459,"sourceCodeEnd":495,"githubUrl":"https://github.com/sqlalchemy/sqlalchemy/blob/d9b44cb731bd27e6e82c99a3c0fb598214e8e7ff/lib/sqlalchemy/sql/dml.py#L459-L495","documentation":"The base DML class (`UpdateBase`) defines `params()` purely to raise `NotImplementedError`; it is overridden only by `ValuesBase` (INSERT/UPDATE) where it actually supplies SET/VALUES. Calling `.params(...)` on a `delete()`, or calling it on an INSERT/UPDATE before the `ValuesBase` machinery is engaged, hits this stub. SQLAlchemy deliberately does not let `params()` set row values for DML — values go through `.values()`.","triggerScenarios":"Calling `stmt = table.delete().where(...)` then `stmt.params(x=1)`; calling `.params()` on a raw `insert()`/`update()` object that has not been built via `ValuesBase`; using the Core/legacy `.params(bind=value)` style (a `select()` idiom) on a DML statement instead of `.values(...)`.","commonSituations":"Developers porting `select().params(...)` patterns to INSERT/UPDATE; mixing the old `bindparam`/`params` query style with 2.0-style DML builders; passing a dict of column values via `.params()` because it 'looks like' parameter binding; ORM bulk operations code that assumed `params()` works uniformly.","solutions":["For INSERT/UPDATE, replace `.params(**params)` with `.values(**params)` (the error message itself recommends this).","For DELETE, remove the `.params()` call entirely; bind values via `where(table.c.id == bindparam('id'))` plus execution-time parameters, or use `bindparam` literals.","If you need runtime-bound literal values inside a DML statement, use `bindparam('name', value=...)` inside `.values()` and pass the actual values at `connection.execute(stmt, params)`.","For a Core SELECT, keep using `.params()` — this error only fires for DML; verify the statement type with `type(stmt)`."],"exampleFix":"# before\nstmt = users.update().where(users.c.id == 5).params(name=\"bob\")\n# raises: params() is not supported for INSERT/UPDATE/DELETE\n\n# after\nstmt = users.update().where(users.c.id == 5).values(name=\"bob\")","handlingStrategy":"validation","validationCode":"from sqlalchemy.sql.dml import Insert, Update\n\ndef set_parameters(stmt, parameters):\n    \"\"\"Route to the correct method: .values() for DML, .params() for SELECT.\"\"\"\n    if isinstance(stmt, (Insert, Update)):\n        return stmt.values(**parameters)\n    # DELETE has no VALUES; pass params for execution-time bind instead\n    return stmt.params(**parameters) if hasattr(stmt, \"params\") else stmt\n\n# usage:\n# stmt = users.update().where(users.c.id == 1)\n# stmt = set_parameters(stmt, {\"name\": \"wendy\"})   # -> stmt.values(...)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never call .params() on Insert/Update/Delete objects; DML uses .values(**params).","When writing helper functions that accept arbitrary statements, branch on isinstance(stmt, (Insert, Update, Delete)) before choosing .params() vs .values().","Remember DELETE has no SET clause — supply bind values at connection.execute() time instead.","Keep a single helper (as above) so the routing rule lives in one place."],"tags":["sqlalchemy","sql-core","dml","insert","update","delete","parameters"],"analyzedSha":"d9b44cb731bd27e6e82c99a3c0fb598214e8e7ff","analyzedAt":"2026-08-01T17:20:52.075Z","schemaVersion":2}