Textualize/textual · error · WrongType
Node matching {query_selector!r} is the wrong type; expected
Error message
Node matching {query_selector!r} is the wrong type; expected type {expect_type.__name__!r}, found {node} What it means
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.
Source
Thrown at src/textual/dom.py:1500
base_node = self._get_dom_base()
if isinstance(selector, str):
query_selector = selector
else:
query_selector = selector.__name__
if is_id_selector(query_selector):
cache_key = (base_node._nodes._updates, query_selector, expect_type)
cached_result = base_node._query_one_cache.get(cache_key)
if cached_result is not None:
return cached_result
if (
node := walk_breadth_search_id(
base_node, query_selector[1:], with_root=False
)
) is not None:
if expect_type is not None and not isinstance(node, expect_type):
raise WrongType(
f"Node matching {query_selector!r} is the wrong type; expected type {expect_type.__name__!r}, found {node}"
)
base_node._query_one_cache[cache_key] = node
return node
raise NoMatches(f"No nodes match {query_selector!r} on {base_node!r}")
try:
selector_set = parse_selectors(query_selector)
except TokenError:
raise InvalidQueryFormat(
f"Unable to parse {query_selector!r} as a query; check for syntax errors"
) from None
if all(selectors.is_simple for selectors in selector_set):
cache_key = (base_node._nodes._updates, query_selector, expect_type)
cached_result = base_node._query_one_cache.get(cache_key)
if cached_result is not None:
return cached_resultView on GitHub (pinned to 06dbeef4bb)
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
Example fix
# before
self.query_one('#name', Input) # WrongType: it's a Label
# after
self.query_one('#name', Label)
# or change compose() to mount an Input with id='name' Defensive patterns
Strategy: type-guard
Validate before calling
node = walk_to_find(base, '#foo')
from textual.widget import Widget
if node is not None and not isinstance(node, ExpectedType):
fix_selector_or_compose() Type guard
def node_is(node, expect_type) -> bool:
return isinstance(node, expect_type) Try / catch
from textual.css.query import WrongType, NoMatches
try:
w = self.query_one('#foo', Input)
except WrongType:
w = self.query_one('#foo') # untyped, handle dynamically
except NoMatches:
w = None Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Query value is the wrong type; expected type {expect_type.__
- No nodes match {self!r} on {self.node!r}
- No nodes match {self!r} on dom{self.node!r}
- Query value is the wrong type; expected type {expect_type.__
- No nodes match {query_selector!r} on {base_node!r}
AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27).
Data as JSON: /api/errors/4582ed00fd5236a0.
Report an issue: GitHub.