Textualize/textual · error · InvalidQueryFormat
Unable to parse {query_selector!r} as a query; check for syn
Error message
Unable to parse {query_selector!r} as a query; check for syntax errors What it means
query_one raises InvalidQueryFormat when the selector string cannot be tokenized/parsed by textual's CSS selector parser (TokenError from parse_selectors). This is a syntax error in the query, not a matching failure.
Source
Thrown at src/textual/dom.py:1510
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_result
else:
cache_key = None
for node in walk_breadth_first(base_node, with_root=False):
if not match(selector_set, node):
continue
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}"
)View on GitHub (pinned to 06dbeef4bb)
Solutions
- Fix the selector syntax — use simple supported forms like '#id', '.class', 'Type', 'Type#id'
- If constructing selectors dynamically, validate/strip components before joining
- For type queries, pass the class itself (query_one(Input)) instead of a hand-built string
Example fix
# before
self.query_one('Input#name extra:') # unparseable
# after
self.query_one('Input#name') Defensive patterns
Strategy: validation
Validate before calling
from textual.css.tokenize import parse_selectors
try:
parse_selectors(selector)
except Exception:
selector = sanitize(selector) # or raise a clear config error
self.query_one(selector) Type guard
def is_valid_selector(s: str) -> bool:
try:
parse_selectors(s)
return True
except Exception:
return False Try / catch
from textual.css.query import InvalidQueryFormat
try:
w = self.query_one(selector)
except InvalidQueryFormat as e:
raise ConfigError(f'bad selector {selector!r}') from e Prevention
- Use static selector literals where possible
- Validate dynamically built selectors in tests
- Pass classes instead of strings for type queries
When it happens
Trigger: Passing a malformed selector to query_one: unbalanced brackets, stray characters, invalid combinators, or a type name that isn't a valid identifier.
Common situations: Building selectors dynamically from user input or f-strings that produce empty/invalid fragments; copying browser-CSS selectors with syntax textual doesn't support; string concatenation bugs leaving trailing characters.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Unable to parse filter {filter!r} as query
- The message class must have a 'control' to match with the on
- The attribute {attribute!r} can't be matched; have you added
- Query value is the wrong type; expected type {expect_type.__
- No nodes match {self!r} on {self.node!r}
AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27).
Data as JSON: /api/errors/787d83489f9cb1e1.
Report an issue: GitHub.