sqlalchemy/alembic · error · NotImplementedError
Autogenerate rendering of SQL Expression language…
Error message
Autogenerate rendering of SQL Expression language constructs not supported here; please use a plain SQL string
What it means
The ExecuteSQLOp renderer raises NotImplementedError when op.execute() receives a SQLAlchemy expression construct (not a plain string) during autogenerate. Alembic's autogenerate DDL rendering can only emit op.execute('literal sql string'); it cannot serialize arbitrary SQL Expression Language elements into migration source code.
Solutions
- Pass a plain SQL string to op.execute(): op.execute('UPDATE t SET col = 1').
- If you have a SQLAlchemy expression, compile it to a string first: op.execute(str(my_expr.compile(dialect=bind.dialect))).
- Keep data-migration execute() calls authored manually as raw SQL strings rather than expressions.
Example fix
# before
from sqlalchemy import text
op.execute(text('UPDATE accounts SET active = true'))
# after (plain string, autogenerate-safe)
op.execute('UPDATE accounts SET active = true') Defensive patterns
Strategy: type-guard
Validate before calling
def execute_for_autogenerate(op, sql):
if not isinstance(sql, str):
sql = str(sql.compile(compile_kwargs={'literal_binds': True}))
op.execute(sql) Type guard
def is_plain_sql_string(value) -> bool:
return isinstance(value, str) Prevention
- Always pass plain SQL strings to op.execute() in migrations that may be autogenerated.
- Compile SQLAlchemy expressions to strings with literal_binds before passing to op.execute().
- Keep data-migration execute() calls as authored raw SQL, not expression objects.
When it happens
Trigger: Calling op.execute(some_select_or_text_object) inside a revision that is being processed by autogenerate (e.g., via process_revision_directives) where the sqltext is a Select, Insert, or text() construct rather than a str.
Common situations: Custom process_revision_directives hooks that inject op.execute() calls with expression objects; data migrations authored with SQLAlchemy expressions that get swept into autogenerate output.
Related errors
- Can only return single object for DowngradeOps traverse
- Can only return single object for UpgradeOps traverse
- can't return inspector as this AutogenContext has no…
- Duplicate table keys across multiple MetaData objects
- no dispatch function for object
AI-assisted analysis of sqlalchemy/alembic@5551b5d35f (2026-08-11).
Data as JSON: /api/errors/a6e1d29a71a4eadb.
Report an issue: GitHub.
Appendix: source
Thrown at alembic/autogenerate/render.py:1186
("name", repr(_render_gen_name(autogen_context, constraint.name)))
)
return "%(prefix)sCheckConstraint(%(sqltext)s%(opts)s)" % {
"prefix": _sqlalchemy_autogenerate_prefix(autogen_context),
"opts": (
", " + (", ".join("%s=%s" % (k, v) for k, v in opts))
if opts
else ""
),
"sqltext": _render_potential_expr(
constraint.sqltext, autogen_context, wrap_in_element=False
),
}
@renderers.dispatch_for(ops.ExecuteSQLOp)
def _execute_sql(autogen_context: AutogenContext, op: ops.ExecuteSQLOp) -> str:
if not isinstance(op.sqltext, str):
raise NotImplementedError(
"Autogenerate rendering of SQL Expression language constructs "
"not supported here; please use a plain SQL string"
)
return "{prefix}execute({sqltext!r})".format(
prefix=_alembic_autogenerate_prefix(autogen_context),
sqltext=op.sqltext,
)
renderers = default_renderers.branch()
View on GitHub (pinned to 5551b5d35f)