sqlalchemy/sqlalchemy · error · NotImplementedError
Extension {type(self).__name__} cannot be applied to update
Error message
Extension {type(self).__name__} cannot be applied to update What it means
Raised by the base SyntaxExtension.apply_to_update method when a syntax extension that does not override apply_to_update is dispatched against an Update statement. SyntaxExtension subclasses are expected to override only the apply_to_* hooks for statement types they support; the base implementation deliberately raises NotImplementedError so unsupported combinations fail loudly. The error message interpolates the concrete extension class name so you can identify which extension was applied. It is a programming-error class issue, not a data issue.
Source
Thrown at lib/sqlalchemy/sql/base.py:1305
:ref:`examples_syntax_extensions`
:meth:`_sql.Select.apply_syntax_extension_point` and equivalents
in :class:`_dml.Insert`, :class:`_dml.Delete`, :class:`_dml.Update`
""" # noqa: E501
cls = type(self)
return [*(e for e in existing if not isinstance(e, cls)), self] # type: ignore[list-item] # noqa: E501
def apply_to_select(self, select_stmt: Select[Unpack[_Ts]]) -> None:
"""Apply this :class:`.SyntaxExtension` to a :class:`.Select`"""
raise NotImplementedError(
f"Extension {type(self).__name__} cannot be applied to select"
)
def apply_to_update(self, update_stmt: Update) -> None:
"""Apply this :class:`.SyntaxExtension` to an :class:`.Update`"""
raise NotImplementedError(
f"Extension {type(self).__name__} cannot be applied to update"
)
def apply_to_delete(self, delete_stmt: Delete) -> None:
"""Apply this :class:`.SyntaxExtension` to a :class:`.Delete`"""
raise NotImplementedError(
f"Extension {type(self).__name__} cannot be applied to delete"
)
def apply_to_insert(self, insert_stmt: Insert) -> None:
"""Apply this :class:`.SyntaxExtension` to an :class:`_sql.Insert`"""
raise NotImplementedError(
f"Extension {type(self).__name__} cannot be applied to insert"
)
class Executable(roles.StatementRole):
"""Mark a :class:`_expression.ClauseElement` as supporting execution.View on GitHub (pinned to d9b44cb731)
Solutions
- If the extension should support UPDATE, add an apply_to_update(self, update_stmt) method to your SyntaxExtension subclass that mutates update_stmt accordingly.
- If the extension legitimately does not apply to UPDATE, guard the call site so the extension is only applied to SELECT/INSERT/DELETE (check statement type before applying).
- Check that you are passing the correct statement type into apply_syntax_extension_point; you may have accidentally constructed an update() where you intended a select().
Example fix
// before
class MyExtension(SyntaxExtension):
def apply_to_select(self, stmt):
...
stmt = update(table).apply_syntax_extension_point(MyExtension())
// after
class MyExtension(SyntaxExtension):
def apply_to_select(self, stmt):
...
def apply_to_update(self, stmt):
... # mutate stmt
stmt = update(table).apply_syntax_extension_point(MyExtension()) Defensive patterns
Strategy: validation
Validate before calling
from sqlalchemy.sql.dml import Update
# Extensions declare which statement types they support; verify before applying.
_extension_stmt_support = { # ext class -> set of supported dml base classes
# populate from the extension's documentation / _supports_* flags
}
def can_apply_to_update(extension) -> bool:
supported = _extension_stmt_support.get(type(extension))
return supported is None or Update in supported
def safe_apply(stmt, extension):
if isinstance(stmt, Update) and not can_apply_to_update(extension):
# skip or reroute the extension instead of letting compile() raise
return stmt
return extension._annotate_or_apply(stmt) # whatever the apply API is Type guard
from sqlalchemy.sql import dml
def is_update_stmt(obj) -> bool:
"""Narrow obj to a SQLAlchemy Update statement."""
return isinstance(obj, dml.Update) Prevention
- Check the statement type with isinstance(stmt, Update) before calling the extension's apply/annotate method.
- Keep an allow-list of which extensions are valid for each DML type instead of applying blindly.
- Run a dry-compile (str(stmt.compile(engine))) in tests to surface extension mismatches before production.
- Read the extension's docstring: many state explicitly 'valid only for SELECT/INSERT/UPDATE/DELETE'.
When it happens
Trigger: A custom or built-in SyntaxExtension instance (e.g. one registered via apply_syntax_extension_point or returned from an extension hook) that only implements apply_to_select/apply_to_insert/apply_to_delete is applied to an update() construct. Concretely, calling update_stmt.apply_syntax_extension_point(SomeExtension) where SomeExtension lacks an apply_to_update override triggers it when the statement is built or executed.
Common situations: Writing a custom SyntaxExtension to add a dialect-specific SQL clause and forgetting to (or not needing to) support UPDATE. Reusing an extension designed for SELECT across all DML statements. Upgrading SQLAlchemy where extension dispatch changed to route through apply_to_* hooks.
Related errors
- Extension {type(self).__name__} cannot be applied to delete
- Extension {type(self).__name__} cannot be applied to insert
- params() is not supported for INSERT/UPDATE/DELETE statement
- update parameter dictionary must not be empty
- update parameter must be a non-empty dictionary or a ColumnC
AI-assisted analysis of sqlalchemy/sqlalchemy@d9b44cb731 (2026-08-01).
Data as JSON: /data/errors/ce731e0f3950c4f0.json.
Report an issue: GitHub.