{"record":{"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":"exception","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/5551b5d35f985c99cb8f1af2b3c526b050e4c059/alembic/ddl/impl.py#L202-L238","documentation":"DefaultImpl._exec raises TypeError when SQL parameters (params or multiparams) are supplied while the implementation is in as_sql (offline) mode. Offline mode outputs literal SQL text to a script file and cannot bind runtime parameters, so passing bound parameters is disallowed.","triggerScenarios":"Running migrations with `alembic upgrade head --sql` (or migration_context configured with as_sql=True) and executing a statement that carries params/multiparams, e.g. bulk_insert or op.execute with bound parameters in offline mode.","commonSituations":"Data migrations using op.bulk_insert or parameterized op.execute run via --sql in CI; tests that exercise the same migration both online and offline.","solutions":["Use literal_binds so parameters are inlined: compile the statement with compile_kwargs={'literal_binds': True} before executing offline.","Run the migration online (without --sql) so bound parameters execute normally.","For bulk_insert in offline mode, ensure literal_binds is enabled in the migration context configuration."],"exampleFix":"# before (offline --sql)\nop.execute(text('UPDATE t SET c = :v'), params={'v': 5})\n\n# after: inline literals\nfrom sqlalchemy import bindparam\nop.execute('UPDATE t SET c = 5')","handlingStrategy":"validation","validationCode":"from alembic import context\n\ndef safe_execute(op, stmt, params=None):\n    if context.is_offline_mode() and params:\n        raise RuntimeError('Cannot use params in offline mode; inline literals')\n    op.execute(stmt, *([params] if params else []))","typeGuard":"def is_offline(impl) -> bool:\n    return bool(getattr(impl, 'as_sql', False))","tryCatchPattern":null,"preventionTips":["Inline all parameters via literal_binds when generating SQL offline.","Prefer plain SQL strings in migrations that must run both online and offline.","Test migrations with --sql in CI to catch param usage early."],"tags":["offline-mode","as-sql","sql-params","ddl"],"backgroundTag":null,"analyzedSha":"5551b5d35f985c99cb8f1af2b3c526b050e4c059","analyzedAt":"2026-08-11T01:38:46.612Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}