{"record":{"id":"5f7f44fe29b0bd35","repo":"Textualize/textual","slug":"call-to-query-one-resulted-in-more-than-one-matche","errorCode":null,"errorMessage":"Call to query_one resulted in more than one matched node","messagePattern":"Call to query_one resulted in more than one matched node","errorType":"exception","errorClass":"TooManyMatches","httpStatus":null,"severity":"error","filePath":"src/textual/dom.py","lineNumber":1643,"sourceCode":"            cache_key = (base_node._nodes._updates, query_selector, expect_type)\n            cached_result = base_node._query_one_cache.get(cache_key)\n            if cached_result is not None:\n                return cached_result\n        else:\n            cache_key = None\n\n        children = walk_breadth_first(base_node, with_root=False)\n        iter_children = iter(children)\n        for node in iter_children:\n            if not match(selector_set, node):\n                continue\n            if expect_type is not None and not isinstance(node, expect_type):\n                raise WrongType(\n                    f\"Node matching {query_selector!r} is the wrong type; expected type {expect_type.__name__!r}, found {node}\"\n                )\n            for later_node in iter_children:\n                if match(selector_set, later_node):\n                    raise TooManyMatches(\n                        \"Call to query_one resulted in more than one matched node\"\n                    )\n            if cache_key is not None:\n                base_node._query_one_cache[cache_key] = node\n            return node\n\n        raise NoMatches(f\"No nodes match {query_selector!r} on {base_node!r}\")\n\n    if TYPE_CHECKING:\n\n        @overload\n        def query_ancestor(self, selector: str) -> DOMNode: ...\n\n        @overload\n        def query_ancestor(self, selector: type[QueryType]) -> QueryType: ...\n\n        @overload\n        def query_ancestor(","sourceCodeStart":1625,"sourceCodeEnd":1661,"githubUrl":"https://github.com/Textualize/textual/blob/06dbeef4bb70fb718236aa418ed658ef4667a126/src/textual/dom.py#L1625-L1661","documentation":"query_exactly_one (and its TooManyMatches error) guarantees at most one match: after finding a first matching node it continues scanning siblings, and if any later node also matches, TooManyMatches is raised.","triggerScenarios":"Calling query_exactly_one('.item') or query_one('#dup-id'-style broad selectors when two or more nodes in the subtree match — e.g. duplicate classes like two Buttons with class 'primary'.","commonSituations":"Repeatedly mounting widgets with the same classes in a loop; screens accumulating duplicate widgets because a previous one wasn't removed; class-based styling classes reused for looks being used for queries.","solutions":["Use a unique id for the single target and query by '#id'","Remove/clear previously mounted duplicates before mounting new ones (e.g. remove_children then mount)","If multiple matches are expected, use query() and index/filter the results instead of query_exactly_one"],"exampleFix":"# before\nawait self.mount(Button('Go', classes='primary'))\nnode = self.query_exactly_one('.primary')  # TooManyMatches after second mount\n\n# after\nawait self.mount(Button('Go', id='go', classes='primary'))\nnode = self.query_exactly_one('#go')","handlingStrategy":"validation","validationCode":"matches = self.query('.primary')\nif len(matches.nodes) > 1:\n    # narrow the selector before the strict call\n    selector = '#go'\nnode = self.query_exactly_one(selector)","typeGuard":"def is_unique(base, selector: str) -> bool:\n    return len(base.query(selector).nodes) == 1","tryCatchPattern":"from textual.css.query import TooManyMatches, NoMatches\ntry:\n    node = self.query_exactly_one('#go')\nexcept TooManyMatches:\n    node = self.query('#go').first()  # or fix duplicates\nexcept NoMatches:\n    node = None","preventionTips":["Give singleton widgets unique ids","Remove old widgets before re-mounting","Reserve styling classes for CSS, ids for queries"],"tags":["textual","query","too-many-matches","dom"],"backgroundTag":"duplicate-element-match","analyzedSha":"06dbeef4bb70fb718236aa418ed658ef4667a126","analyzedAt":"2026-08-27T02:36:57.214Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}