{"record":{"id":"4582ed00fd5236a0","repo":"Textualize/textual","slug":"node-matching-query-selector-r-is-the-wrong-type","errorCode":null,"errorMessage":"Node matching {query_selector!r} is the wrong type; expected type {expect_type.__name__!r}, found {node}","messagePattern":"Node matching (.+?) is the wrong type; expected type (.+?), found (.+?)","errorType":"exception","errorClass":"WrongType","httpStatus":null,"severity":"error","filePath":"src/textual/dom.py","lineNumber":1500,"sourceCode":"        base_node = self._get_dom_base()\n\n        if isinstance(selector, str):\n            query_selector = selector\n        else:\n            query_selector = selector.__name__\n\n        if is_id_selector(query_selector):\n            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            if (\n                node := walk_breadth_search_id(\n                    base_node, query_selector[1:], with_root=False\n                )\n            ) is not None:\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                base_node._query_one_cache[cache_key] = node\n                return node\n            raise NoMatches(f\"No nodes match {query_selector!r} on {base_node!r}\")\n\n        try:\n            selector_set = parse_selectors(query_selector)\n        except TokenError:\n            raise InvalidQueryFormat(\n                f\"Unable to parse {query_selector!r} as a query; check for syntax errors\"\n            ) from None\n\n        if all(selectors.is_simple for selectors in selector_set):\n            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","sourceCodeStart":1482,"sourceCodeEnd":1518,"githubUrl":"https://github.com/Textualize/textual/blob/06dbeef4bb70fb718236aa418ed658ef4667a126/src/textual/dom.py#L1482-L1518","documentation":"query_one found a node matching an #id selector, but the node is not an instance of the expected type given via the expect_type argument/overload, so WrongType is raised instead of silently returning a mismatched object.","triggerScenarios":"Calling query_one('#foo', ExpectedType) where the node with id 'foo' is a different widget class; using the typed overload query_one('#foo', Input) when #foo is a Label.","commonSituations":"Changing a widget's class in compose() without updating queries; querying by id that collides across screens; type narrowing via query_one(str, type) with a stale type after refactors.","solutions":["Update the query's expected type to the actual widget class, or fix compose() so the widget with that id is the expected class","Use query() with isinstance filtering if multiple types are acceptable","Ensure ids are unique per screen so queries resolve predictably"],"exampleFix":"# before\nself.query_one('#name', Input)  # WrongType: it's a Label\n\n# after\nself.query_one('#name', Label)\n# or change compose() to mount an Input with id='name'","handlingStrategy":"type-guard","validationCode":"node = walk_to_find(base, '#foo')\nfrom textual.widget import Widget\nif node is not None and not isinstance(node, ExpectedType):\n    fix_selector_or_compose()","typeGuard":"def node_is(node, expect_type) -> bool:\n    return isinstance(node, expect_type)","tryCatchPattern":"from textual.css.query import WrongType, NoMatches\ntry:\n    w = self.query_one('#foo', Input)\nexcept WrongType:\n    w = self.query_one('#foo')  # untyped, handle dynamically\nexcept NoMatches:\n    w = None","preventionTips":["Keep query types in sync with compose() definitions","Prefer unique ids so queries resolve deterministically","Search for all query_one('#foo', T) uses before changing a widget class"],"tags":["textual","query","type-mismatch","dom"],"backgroundTag":"query-type-mismatch","analyzedSha":"06dbeef4bb70fb718236aa418ed658ef4667a126","analyzedAt":"2026-08-27T02:36:57.214Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}