{"record":{"id":"04dc855ed27485b5","repo":"Textualize/textual","slug":"no-nodes-match-self-r-on-dom-self-node-r","errorCode":null,"errorMessage":"No nodes match {self!r} on dom{self.node!r}","messagePattern":"No nodes match (.+?) on dom(.+?)","errorType":"validation","errorClass":"NoMatches","httpStatus":null,"severity":"error","filePath":"src/textual/css/query.py","lineNumber":323,"sourceCode":"\n    def last(\n        self, expect_type: type[ExpectType] | None = None\n    ) -> 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]:","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/Textualize/textual/blob/06dbeef4bb70fb718236aa418ed658ef4667a126/src/textual/css/query.py#L305-L341","documentation":"last() raises NoMatches when the query returned an empty node list, mirroring first()'s empty check but for the last-matched node accessor. The message (with its quirky 'dom' wording) includes the query repr and node for diagnosis.","triggerScenarios":"`screen.query(\"DataTable\").last()` with no DataTable mounted; selectors referencing widgets on other screens; querying after remove() of the only match.","commonSituations":"Same family as first()'s NoMatches: timing (not yet mounted), misspelled selectors, or querying the wrong node subtree.","solutions":["Confirm the target widget exists and is mounted under the queried node at call time","Defer the query until after mount/compose (call_after_refresh)","Catch NoMatches to handle 'not present yet' gracefully"],"exampleFix":"# before\nrow = self.query(\"DataTable .row--highlight\").last()  # NoMatches\n# after\nfrom textual.css.query import NoMatches\ntry:\n    row = self.query(\"DataTable .row--highlight\").last()\nexcept NoMatches:\n    row = None","handlingStrategy":"try-catch","validationCode":"q = screen.query(selector)\nnode = q.nodes[-1] if q.nodes else None","typeGuard":null,"tryCatchPattern":"from textual.css.query import NoMatches\ntry:\n    node = q.last()\nexcept NoMatches:\n    node = None","preventionTips":["Check .nodes emptiness before first()/last() on optional widgets"],"tags":["textual","query","no-matches","dom"],"backgroundTag":"element-not-found","analyzedSha":"06dbeef4bb70fb718236aa418ed658ef4667a126","analyzedAt":"2026-08-27T02:36:57.214Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}