Textualize/textual · error · WrongType

Descendant with id={id!r} is the wrong type; expected type {

Error message

Descendant with id={id!r} is the wrong type; expected type {expect_type.__name__!r}, found {widget}

What it means

Deep lookup variant: get_widget_by_id uses query_one('#id') and then checks expect_type; WrongType signals the descendant exists but is not the expected type.

Source

Thrown at src/textual/widget.py:1149

        """Return the first descendant widget with the given ID.

        Performs a depth-first search rooted at this widget.

        Args:
            id: The ID to search for in the subtree.
            expect_type: Require the object be of the supplied type, or None for any type.

        Returns:
            The first descendant encountered with this ID.

        Raises:
            NoMatches: if no children could be found for this ID.
            WrongType: if the wrong type was found.
        """

        widget = self.query_one(f"#{id}")
        if expect_type is not None and not isinstance(widget, expect_type):
            raise WrongType(
                f"Descendant with id={id!r} is the wrong type; expected type {expect_type.__name__!r}, found {widget}"
            )
        return widget

    def get_child_by_type(self, expect_type: type[ExpectType]) -> ExpectType:
        """Get the first immediate child of a given type.

        Only returns exact matches, and so will not match subclasses of the given type.

        Args:
            expect_type: The type of the child to search for.

        Raises:
            NoMatches: If no matching child is found.

        Returns:
            The first immediate child widget with the expected type.
        """

View on GitHub (pinned to 06dbeef4bb)

Solutions

  1. Align expect_type with the actual widget type
  2. Rename ids so each type has a distinct id
  3. Use query_one with a compound selector like "#footer.footer-class"

Example fix

# before
w = self.get_widget_by_id("footer", expect_type=Footer)
# after
w = self.get_widget_by_id("footer", expect_type=MyCustomFooter)
Defensive patterns

Strategy: type-guard

Validate before calling

widget = self.query_one(f"#{id}")
if isinstance(widget, expect_type):
    use(widget)

Type guard

def descendant_is_type(root: Widget, id: str, t: type) -> bool:
    return isinstance(root.query_one(f"#{id}"), t)

Try / catch

try:
    w = self.get_widget_by_id("x", expect_type=T)
except WrongType:
    w = self.query_one("#x")  # handle actual type

Prevention

When it happens

Trigger: get_widget_by_id("footer", expect_type=Footer) where a different widget type holds that id somewhere in the subtree.

Common situations: Reusing an id across different screens/layouts after refactors; custom replacements for stock widgets keeping the same id.

Related errors


AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27). Data as JSON: /api/errors/2b363cca7a62953b. Report an issue: GitHub.