{"id":"400c5fcc53198109","repo":"sqlalchemy/alembic","slug":"cannot-call-run-async-in-sql-mode","errorCode":null,"errorMessage":"Cannot call run_async in SQL mode","messagePattern":"Cannot call run_async in SQL mode","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"alembic/operations/base.py","lineNumber":577,"sourceCode":"\n        The async connection passed to the callable shares the same\n        transaction as the connection running in the migration context.\n\n        Any additional arg or kw_arg passed to this function are passed\n        to the provided async function.\n\n        .. versionadded: 1.11\n\n        .. note::\n\n            This method can be called only when alembic is called using\n            an async dialect.\n        \"\"\"\n        if not sqla_compat.sqla_14_18:\n            raise NotImplementedError(\"SQLAlchemy 1.4.18+ required\")\n        sync_conn = self.get_bind()\n        if sync_conn is None:\n            raise NotImplementedError(\"Cannot call run_async in SQL mode\")\n        if not sync_conn.dialect.is_async:\n            raise ValueError(\"Cannot call run_async with a sync engine\")\n        from sqlalchemy.ext.asyncio import AsyncConnection\n        from sqlalchemy.util import await_only\n\n        async_conn = AsyncConnection._retrieve_proxy_for_target(sync_conn)\n        return await_only(async_function(async_conn, *args, **kw_args))\n\n\nclass Operations(AbstractOperations):\n    \"\"\"Define high level migration operations.\n\n    Each operation corresponds to some schema migration operation,\n    executed against a particular :class:`.MigrationContext`\n    which in turn represents connectivity to a database,\n    or a file output stream.\n\n    While :class:`.Operations` is normally configured as","sourceCodeStart":559,"sourceCodeEnd":595,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/44fb3450330204b222ff05135e1fbbbdb28c44db/alembic/operations/base.py#L559-L595","documentation":"run_async needs a real async-capable connection to wrap; in offline (SQL) mode get_bind() returns None and there is no underlying DBAPI connection to proxy. The guard rejects the call before attempting to await on a non-existent connection.","triggerScenarios":"Calling op.run_async(...) inside a migration context configured with as_sql=True (e.g. 'alembic upgrade head --sql'), or any context where MigrationContext.bind is None.","commonSituations":"Generating an offline SQL script for a migration that contains run_async; an env.py that conditionally goes offline but still runs the migration body.","solutions":["Run the migration online (remove --sql / set as_sql=False) so a real connection exists.","For offline SQL output, replace the run_async block with a plain op.execute('...') string.","Restructure env.py so run_async paths are skipped in offline mode."],"exampleFix":"// before\n# invoked as: alembic upgrade head --sql\nop.run_async(prepare_async_data)  # -> NotImplementedError\n// after\n# run online instead\nwith engine.connect() as conn:\n    context.configure(connection=conn)\n    ...","handlingStrategy":"validation","validationCode":"if context.is_offline_mode() or op.get_bind() is None:\n    raise RuntimeError(\"op.run_async requires a live (online) connection\")","typeGuard":"def has_online_bind(op) -> bool:\n    return op.get_bind() is not None","tryCatchPattern":null,"preventionTips":["Branch on context.is_offline_mode() before calling run_async.","Strip run_async blocks from offline SQL generation paths.","Document which migrations require online execution."],"tags":["run-async","offline-mode","connection"],"analyzedSha":"44fb3450330204b222ff05135e1fbbbdb28c44db","analyzedAt":"2026-08-04T19:57:10.248Z","schemaVersion":2}