{"record":{"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/5551b5d35f985c99cb8f1af2b3c526b050e4c059/alembic/util/langhelpers.py#L112-L148","documentation":"Raised as NameError by the module-level proxy mechanism in ModuleClsMeta when a proxied function (e.g. op.batch_alter_table, commands.upgrade) is invoked before _install_proxy() has been called. Alembic uses lazy proxies so that 'from alembic import op' works at import time — the proxy defers to a real object that is installed at runtime when a migration context is active. Calling these at import time or outside a migration context triggers this.","triggerScenarios":"Calling op.X() or commands.X() at Python module top level / import time rather than inside a migration function (upgrade/downgrade). Also triggered by running migration code outside the alembic runner context (e.g. importing a migration module directly and calling upgrade()). The proxy function at langhelpers.py:197-201 tries to read _proxy and catches NameError, calling _name_error.","commonSituations":"Writing migration helper logic at module scope instead of inside def upgrade(). Importing alembic.op in a utility module and calling it from outside a migration. Testing migration code by importing it directly without setting up a MigrationContext. Refactoring that accidentally moves op calls outside function scope.","solutions":["Move all op.X() calls inside the upgrade() or downgrade() functions, not at module level.","If testing migrations, use alembic.testing or set up an actual MigrationContext before invoking migration code.","Ensure 'from alembic import op' is only used inside migration scripts that are run by the alembic runner.","Check that the env.py file properly calls context.configure() and context.run_migrations() which install the proxy."],"exampleFix":"# before\nfrom alembic import op\nimport sqlalchemy as sa\n\nop.add_column('users', sa.Column('email', sa.String()))  # module-level!\n\ndef upgrade():\n    pass\n\n# after\nfrom alembic import op\nimport sqlalchemy as sa\n\ndef upgrade():\n    op.add_column('users', sa.Column('email', sa.String()))","handlingStrategy":"validation","validationCode":"import inspect\n\ndef validate_op_calls_in_functions(module_source):\n    \"\"\"Check that op.X() calls are inside function definitions, not at module level.\"\"\"\n    import ast\n    tree = ast.parse(module_source)\n    for node in ast.iter_child_nodes(tree):\n        if isinstance(node, ast.Expr):\n            if isinstance(node.value, ast.Call):\n                func = node.value.func\n                if isinstance(func, ast.Attribute) and isinstance(func.value, ast.Name) and func.value.id == 'op':\n                    return False  # module-level op call found\n    return True","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always place op.X() calls inside def upgrade() / def downgrade() functions.","Never call migration operations at module import time.","When testing migrations, use Alembic's test runner or MigrationContext instead of importing migration modules directly."],"tags":["alembic","proxy","lazy-init","migration-scripts","nameerror"],"backgroundTag":null,"analyzedSha":"5551b5d35f985c99cb8f1af2b3c526b050e4c059","analyzedAt":"2026-08-11T01:38:46.612Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}