sqlalchemy/alembic · error · NameError
Can't invoke function
Error message
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.
What it means
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.
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.
Example fix
# before
from alembic import op
import sqlalchemy as sa
op.add_column('users', sa.Column('email', sa.String())) # module-level!
def upgrade():
pass
# after
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column('users', sa.Column('email', sa.String())) Defensive patterns
Strategy: validation
Validate before calling
import inspect
def validate_op_calls_in_functions(module_source):
"""Check that op.X() calls are inside function definitions, not at module level."""
import ast
tree = ast.parse(module_source)
for node in ast.iter_child_nodes(tree):
if isinstance(node, ast.Expr):
if isinstance(node.value, ast.Call):
func = node.value.func
if isinstance(func, ast.Attribute) and isinstance(func.value, ast.Name) and func.value.id == 'op':
return False # module-level op call found
return True Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Can't change down_revision on a refresh operation.
- missing required positional argument
- A plugin named is already registered
- Can not set dispatch function for object
- Can't drop table in batch mode
AI-assisted analysis of sqlalchemy/alembic@5551b5d35f (2026-08-11).
Data as JSON: /api/errors/037b52f27caec2c2.
Report an issue: GitHub.
Appendix: source
Thrown at alembic/util/langhelpers.py:130
meth = getattr(cls, methname)
if callable(meth):
locals_[methname] = cls._create_method_proxy(
methname, globals_, locals_
)
else:
attr_names.add(methname)
@classmethod
def _create_method_proxy(
cls,
name: str,
globals_: MutableMapping[str, Any],
locals_: MutableMapping[str, Any],
) -> Callable[..., Any]:
fn = getattr(cls, name)
def _name_error(name: str, from_: Exception) -> NoReturn:
raise NameError(
"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."
% (name, cls.__name__)
) from from_
globals_["_name_error"] = _name_error
translations = getattr(fn, "_legacy_translations", [])
if translations:
spec = inspect_getfullargspec(fn)
if spec[0] and spec[0][0] == "self":
spec[0].pop(0)
outer_args = inner_args = "*args, **kw"
translate_str = "args, kw = _translate(%r, %r, %r, args, kw)" % (
fn.__name__,View on GitHub (pinned to 5551b5d35f)