{"id":"037b52f27caec2c2","repo":"sqlalchemy/alembic","slug":"can-t-invoke-function-s-as-the-proxy-object-ha","errorCode":null,"errorMessage":"Can't invoke function '%s', as the proxy object has not yet been established for the Alembic '%s' class.  Try placing this code inside a callable.","messagePattern":"Can't invoke function '(.+?)', as the proxy object has not yet been established for the Alembic '(.+?)' class\\.  Try placing this code inside a callable\\.","errorType":"exception","errorClass":"NameError","httpStatus":null,"severity":"error","filePath":"alembic/util/langhelpers.py","lineNumber":130,"sourceCode":"            meth = getattr(cls, methname)\n            if callable(meth):\n                locals_[methname] = cls._create_method_proxy(\n                    methname, globals_, locals_\n                )\n            else:\n                attr_names.add(methname)\n\n    @classmethod\n    def _create_method_proxy(\n        cls,\n        name: str,\n        globals_: MutableMapping[str, Any],\n        locals_: MutableMapping[str, Any],\n    ) -> Callable[..., Any]:\n        fn = getattr(cls, name)\n\n        def _name_error(name: str, from_: Exception) -> NoReturn:\n            raise NameError(\n                \"Can't invoke function '%s', as the proxy object has \"\n                \"not yet been \"\n                \"established for the Alembic '%s' class.  \"\n                \"Try placing this code inside a callable.\"\n                % (name, cls.__name__)\n            ) from from_\n\n        globals_[\"_name_error\"] = _name_error\n\n        translations = getattr(fn, \"_legacy_translations\", [])\n        if translations:\n            spec = inspect_getfullargspec(fn)\n            if spec[0] and spec[0][0] == \"self\":\n                spec[0].pop(0)\n\n            outer_args = inner_args = \"*args, **kw\"\n            translate_str = \"args, kw = _translate(%r, %r, %r, args, kw)\" % (\n                fn.__name__,","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/44fb3450330204b222ff05135e1fbbbdb28c44db/alembic/util/langhelpers.py#L112-L148","documentation":"Raised as NameError by the _name_error closure inside ModuleClsProxy._create_method_proxy (langhelpers.py:130) when a module-level proxy function (e.g. alembic.op.create_table) is invoked before _install_proxy has established the per-class _proxy object. The proxy functions are generated to defer to the real Operations instance, which only exists inside a migration context; calling them outside upgrade()/downgrade() trips this guard.","triggerScenarios":"Importing alembic.op and calling op.add_column(...) at module import time or in a test without an active migration context; referencing op.* in env.py before context.begin_transaction()/run_migrations(); calling Operations methods through the module proxy without having constructed an Operations bound to a MigrationContext.","commonSituations":"Writing unit tests that call op functions directly; refactor that moves op calls outside the upgrade() function body; env.py that eagerly invokes op or context APIs before the migration context is configured.","solutions":["Move all op.* calls inside the body of an upgrade()/downgrade() function so they execute within an active migration context.","In tests, use Operations(context) / op._proxy setup or the migration_context fixture to establish the proxy before calling.","In env.py, ensure context.configure(...) and context.run_migrations() wrap any op usage.","Check that nothing imports and immediately invokes op at module top level."],"exampleFix":"# before: op called at import time, no proxy yet\nfrom alembic import op\nop.create_table('my_table', ...)  # NameError\n\n# after: called inside upgrade()\nfrom alembic import op\ndef upgrade():\n    op.create_table('my_table', ...)","handlingStrategy":"validation","validationCode":"from alembic.operations import Operations\nfrom alembic.runtime.migration import MigrationContext\n\ndef op_is_ready() -> bool:\n    proxy = getattr(Operations, '_proxy', None)\n    return proxy is not None\n\n# in tests:\nwith MigrationContext.configure(connection) as ctx:\n    Operations(ctx)  # installs the proxy\n    assert op_is_ready()","typeGuard":null,"tryCatchPattern":"# Not recommended to catch — fix the call site instead.\n# If unavoidable:\ntry:\n    op.create_table('t', sa.Column('id', sa.Integer))\nexcept NameError as e:\n    if 'proxy object has not yet been established' in str(e):\n        raise RuntimeError('op called outside migration context') from e\n    raise","preventionTips":["Keep all op.* calls inside upgrade()/downgrade() function bodies.","In tests, establish a MigrationContext + Operations before invoking op.","Lint for module-level op.* calls (they almost always indicate a bug)."],"tags":["alembic","operations","proxy","migration-context","api-misuse"],"analyzedSha":"44fb3450330204b222ff05135e1fbbbdb28c44db","analyzedAt":"2026-08-04T19:57:10.248Z","schemaVersion":2}