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

  1. If the extension should support UPDATE, add an apply_to_update(self, update_stmt) method to your SyntaxExtension subclass that mutates update_stmt accordingly.
  2. 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).
  3. 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

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


AI-assisted analysis of sqlalchemy/sqlalchemy@d9b44cb731 (2026-08-01). Data as JSON: /data/errors/ce731e0f3950c4f0.json. Report an issue: GitHub.