{"id":"ce731e0f3950c4f0","repo":"sqlalchemy/sqlalchemy","slug":"extension-type-self-name-cannot-be-applied-ce731e","errorCode":null,"errorMessage":"Extension {type(self).__name__} cannot be applied to update","messagePattern":"Extension (.+?) cannot be applied to update","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"lib/sqlalchemy/sql/base.py","lineNumber":1305,"sourceCode":"\n            :ref:`examples_syntax_extensions`\n\n            :meth:`_sql.Select.apply_syntax_extension_point` and equivalents\n            in :class:`_dml.Insert`, :class:`_dml.Delete`, :class:`_dml.Update`\n\n        \"\"\"  # noqa: E501\n        cls = type(self)\n        return [*(e for e in existing if not isinstance(e, cls)), self]  # type: ignore[list-item] # noqa: E501\n\n    def apply_to_select(self, select_stmt: Select[Unpack[_Ts]]) -> None:\n        \"\"\"Apply this :class:`.SyntaxExtension` to a :class:`.Select`\"\"\"\n        raise NotImplementedError(\n            f\"Extension {type(self).__name__} cannot be applied to select\"\n        )\n\n    def apply_to_update(self, update_stmt: Update) -> None:\n        \"\"\"Apply this :class:`.SyntaxExtension` to an :class:`.Update`\"\"\"\n        raise NotImplementedError(\n            f\"Extension {type(self).__name__} cannot be applied to update\"\n        )\n\n    def apply_to_delete(self, delete_stmt: Delete) -> None:\n        \"\"\"Apply this :class:`.SyntaxExtension` to a :class:`.Delete`\"\"\"\n        raise NotImplementedError(\n            f\"Extension {type(self).__name__} cannot be applied to delete\"\n        )\n\n    def apply_to_insert(self, insert_stmt: Insert) -> None:\n        \"\"\"Apply this :class:`.SyntaxExtension` to an :class:`_sql.Insert`\"\"\"\n        raise NotImplementedError(\n            f\"Extension {type(self).__name__} cannot be applied to insert\"\n        )\n\n\nclass Executable(roles.StatementRole):\n    \"\"\"Mark a :class:`_expression.ClauseElement` as supporting execution.","sourceCodeStart":1287,"sourceCodeEnd":1323,"githubUrl":"https://github.com/sqlalchemy/sqlalchemy/blob/d9b44cb731bd27e6e82c99a3c0fb598214e8e7ff/lib/sqlalchemy/sql/base.py#L1287-L1323","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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()."],"exampleFix":"// before\nclass MyExtension(SyntaxExtension):\n    def apply_to_select(self, stmt):\n        ...\n\nstmt = update(table).apply_syntax_extension_point(MyExtension())\n\n// after\nclass MyExtension(SyntaxExtension):\n    def apply_to_select(self, stmt):\n        ...\n    def apply_to_update(self, stmt):\n        ...  # mutate stmt\n\nstmt = update(table).apply_syntax_extension_point(MyExtension())","handlingStrategy":"validation","validationCode":"from sqlalchemy.sql.dml import Update\n\n# Extensions declare which statement types they support; verify before applying.\n_extension_stmt_support = {  # ext class -> set of supported dml base classes\n    # populate from the extension's documentation / _supports_* flags\n}\n\ndef can_apply_to_update(extension) -> bool:\n    supported = _extension_stmt_support.get(type(extension))\n    return supported is None or Update in supported\n\ndef safe_apply(stmt, extension):\n    if isinstance(stmt, Update) and not can_apply_to_update(extension):\n        # skip or reroute the extension instead of letting compile() raise\n        return stmt\n    return extension._annotate_or_apply(stmt)  # whatever the apply API is","typeGuard":"from sqlalchemy.sql import dml\n\ndef is_update_stmt(obj) -> bool:\n    \"\"\"Narrow obj to a SQLAlchemy Update statement.\"\"\"\n    return isinstance(obj, dml.Update)","tryCatchPattern":null,"preventionTips":["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'."],"tags":["sqlalchemy","syntax-extension","dml","update"],"analyzedSha":"d9b44cb731bd27e6e82c99a3c0fb598214e8e7ff","analyzedAt":"2026-08-01T17:20:52.075Z","schemaVersion":2}