{"id":"0bc6e00142b7ba20","repo":"sqlalchemy/alembic","slug":"sql-parameters-not-allowed-with-as-sql","errorCode":null,"errorMessage":"SQL parameters not allowed with as_sql","messagePattern":"SQL parameters not allowed with as_sql","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"alembic/ddl/impl.py","lineNumber":220,"sourceCode":"\n        \"\"\"\n\n    @property\n    def bind(self) -> Connection | None:\n        return self.connection\n\n    def _exec(\n        self,\n        construct: Executable | str,\n        execution_options: Mapping[str, Any] | None = None,\n        multiparams: Sequence[Mapping[str, Any]] | None = None,\n        params: Mapping[str, Any] = util.immutabledict(),\n    ) -> CursorResult | None:\n        if isinstance(construct, str):\n            construct = text(construct)\n        if self.as_sql:\n            if multiparams is not None or params:\n                raise TypeError(\"SQL parameters not allowed with as_sql\")\n\n            compile_kw: dict[str, Any]\n            if self.literal_binds and not isinstance(\n                construct, schema.DDLElement\n            ):\n                compile_kw = dict(compile_kwargs={\"literal_binds\": True})\n            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:","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/44fb3450330204b222ff05135e1fbbbdb28c44db/alembic/ddl/impl.py#L202-L238","documentation":"When the migration context is in as_sql (offline) mode, the impl writes SQL text to a file/stream rather than executing against a database. Bind parameters cannot be rendered to a script because there is no DB to substitute them; only literal SQL (optionally with literal_binds) is emitted. Passing params/multiparams in this mode is therefore rejected.","triggerScenarios":"Calling op.execute(text('...'), params=...) or op.bulk_insert(...) inside an offline (as_sql=True) migration where the operation carries bind parameters; invoking 'alembic upgrade head --sql' over a migration that uses parameterized statements.","commonSituations":"A migration written for online use that calls op.execute(sa.text('UPDATE t SET x=:x'), params={'x': 1}); running it in offline SQL dump mode; using bulk_insert in SQL generation mode with non-literal values without literal_binds.","solutions":["Run the migration online (remove --sql / as_sql) so bind parameters can be executed.","For offline SQL, inline the values: op.execute(\"UPDATE t SET x = 1\").","Set literal_binds=True in the migration context if you need parameterized SQL rendered with literal values."],"exampleFix":"// before\nop.execute(sa.text('UPDATE users SET active = :v'), params={'v': True})\n# run as: alembic upgrade head --sql  -> TypeError\n// after\nop.execute('UPDATE users SET active = true')","handlingStrategy":"validation","validationCode":"if context.is_offline_mode():\n    assert not params and multiparams is None, \"Bind params not allowed in as_sql mode; inline values instead.\"","typeGuard":null,"tryCatchPattern":"try:\n    op.execute(text('...'), params=p)\nexcept TypeError as e:\n    if 'as_sql' in str(e):\n        op.execute(render_literal_sql(stmt, p))\n    else: raise","preventionTips":["Branch on context.is_offline_mode() before parameterized op.execute().","Inline literal values when generating SQL scripts.","Enable literal_binds so parameters render to literals in offline mode."],"tags":["offline-mode","sql-params","as-sql"],"analyzedSha":"44fb3450330204b222ff05135e1fbbbdb28c44db","analyzedAt":"2026-08-04T19:57:10.248Z","schemaVersion":2}