{"record":{"id":"ba1ac0d1bfb4ce02","repo":"Textualize/textual","slug":"query-value-is-the-wrong-type-expected-type-expe-ba1ac0","errorCode":null,"errorMessage":"Query value is the wrong type; expected type {expect_type.__name__!r}, found {last}","messagePattern":"Query value is the wrong type; expected type (.+?), found (.+?)","errorType":"validation","errorClass":"WrongType","httpStatus":null,"severity":"error","filePath":"src/textual/css/query.py","lineNumber":326,"sourceCode":"    ) -> QueryType | ExpectType:\n        \"\"\"Get the *last* matching node.\n\n        Args:\n            expect_type: Require matched node is of this type,\n                or None for any type.\n\n        Raises:\n            WrongType: If the wrong type was found.\n            NoMatches: If there are no matching nodes in the query.\n\n        Returns:\n            The matching Widget.\n        \"\"\"\n        if not self.nodes:\n            raise NoMatches(f\"No nodes match {self!r} on dom{self.node!r}\")\n        last = self.nodes[-1]\n        if expect_type is not None and not isinstance(last, expect_type):\n            raise WrongType(\n                f\"Query value is the wrong type; expected type {expect_type.__name__!r}, found {last}\"\n            )\n        return last\n\n    if TYPE_CHECKING:\n\n        @overload\n        def results(self) -> Iterator[QueryType]: ...\n\n        @overload\n        def results(self, filter_type: type[ExpectType]) -> Iterator[ExpectType]: ...\n\n    def results(\n        self, filter_type: type[ExpectType] | None = None\n    ) -> Iterator[QueryType | ExpectType]:\n        \"\"\"Get query results, optionally filtered by a given type.\n\n        Args:","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/Textualize/textual/blob/06dbeef4bb70fb718236aa418ed658ef4667a126/src/textual/css/query.py#L308-L344","documentation":"last() applies the same expect_type isinstance check as first(), but against the final matched node; on mismatch it raises WrongType naming the expected class and the found node. Both errors can occur on one call — NoMatches if empty, WrongType if the last node's type differs.","triggerScenarios":"`self.query(\"Widget\").last(Static)` where the last widget in the match list is an Input; mixing widget types under one selector then asserting a single type.","commonSituations":"Broad selectors that match heterogeneous widget types combined with a strict expect_type; DOM reordering making a different widget last.","solutions":["Pass the correct/actual type, or a common base class (Widget/Static as appropriate)","Narrow the selector to only the intended widget type (e.g. `\"Static.content\"`)","Omit expect_type and isinstance-check the result when types legitimately vary"],"exampleFix":"# before\nnode = self.query(\".footer-item\").last(Static)  # WrongType (it's a Button)\n# after\nnode = self.query(\".footer-item\").last(Button)","handlingStrategy":"type-guard","validationCode":"q = screen.query(selector)\nnode = q.nodes[-1] if q.nodes and isinstance(q.nodes[-1], Static) else None","typeGuard":"def last_is_type(q, cls) -> bool:\n    return bool(q.nodes) and isinstance(q.nodes[-1], cls)","tryCatchPattern":"from textual.css.query import WrongType\ntry:\n    node = q.last(Static)\nexcept WrongType:\n    node = q.last()","preventionTips":["Narrow selectors by widget type instead of asserting types on broad matches"],"tags":["textual","query","type-mismatch"],"backgroundTag":"query-type-mismatch","analyzedSha":"06dbeef4bb70fb718236aa418ed658ef4667a126","analyzedAt":"2026-08-27T02:36:57.214Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}