kovidgoyal/kitty · warning · ParseException
Extra characters at end of search
Error message
Extra characters at end of search
What it means
The search-query lexer returns leftover unconsumed input after tokenizing; the parser rejects it with ParseException 'Extra characters at end of search'. Usually unbalanced quotes/parens or stray characters the grammar doesn't accept.
Source
Thrown at kitty/search_query_parser.py:191
def token_type(self) -> TokenType:
if self.is_eof():
return TokenType.EOF
return self.tokens[self.current_token].type
def is_eof(self) -> bool:
return self.current_token >= len(self.tokens)
def advance(self) -> None:
self.current_token += 1
def tokenize(self, expr: str) -> list[Token]:
# Strip out escaped backslashes, quotes and parens so that the
# lex scanner doesn't get confused. We put them back later.
for k, v in replacements():
expr = expr.replace(k, v)
tokens, leftover = lex_scanner()(expr)
if leftover:
raise ParseException(_('Extra characters at end of search'))
def unescape(x: str) -> str:
for k, v in replacements():
x = x.replace(v, k[1:])
return x
return [Token(tt, unescape(tv) if tt in (TokenType.WORD, TokenType.QUOTED_WORD) else tv) for tt, tv in tokens]
def parse(self, expr: str, locations: Sequence[str]) -> SearchTreeNode:
self.locations = locations
self.tokens = self.tokenize(expr)
self.current_token = 0
prog = self.or_expression()
if not self.is_eof():
raise ParseException(_('Extra characters at end of search'))
return prog
def or_expression(self) -> SearchTreeNode:View on GitHub (pinned to 6d5d0c4406)
Solutions
- Balance all quotes and parentheses in the search expression
- Escape special characters (backslash, quotes, parens) as the parser expects
- Trim trailing junk/whitespace-specials before submitting
Example fix
# before
parse_query('"unclosed')
# after
parse_query('"unclosed"') Defensive patterns
Strategy: validation
Validate before calling
def balanced(q):
return q.count('"')%2==0 and q.count('(')==q.count(')')
assert balanced(query) Type guard
def is_balanced_query(q: str) -> bool: return q.count('"')%2==0 and q.count('(')==q.count(')') Try / catch
except ParseException: show user a syntax hint and re-prompt
Prevention
- Escape quotes/parens when composing queries from user input
- Test generated queries through the parser before sending to kitty
When it happens
Trigger: Calling search with an expression like '"unclosed' or 'foo )' where escaped-unescape round-tripping leaves trailing tokens the scanner could not consume.
Common situations: Programmatically building search queries without escaping quotes/parens, or user-typed queries with mismatched delimiters.
Related errors
- missing )
- Invalid syntax. Expected a lookup name or a word
- Failed to parse {query!r}, too much recursion required
- not a valid file descriptor number: %#v
- %s is not valid MIME alias specification
AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27).
Data as JSON: /api/errors/e796f21bc5a529c1.
Report an issue: GitHub.