ErrLookupBackground articles › SyntaxError: 'Unexpected token' and 'Unexpected end of input' — why parsers reject your input across libraries

SyntaxError: 'Unexpected token' and 'Unexpected end of input' — why parsers reject your input across libraries

SyntaxError is the class thrown when input cannot be parsed under the expected grammar — the force behind messages like "Unexpected token", "Unexpected end of input", "closing quote is missing", and "Named export not found". Far beyond the JavaScript and Python compilers, it surfaces from template engines (Twig), expression evaluators (pandas eval/query, pytest -m), CSS and XML parsers, WebSocket handshake header parsers (ws), PEP 508 requirement strings in pip, config validators (ultralytics), and module-import analyzers (Vite, Hoppscotch). You meet it whenever a string handed to a library — code, template, stylesheet, header, requirement, or config key — breaks that library's rules for shape, order, or names, and the library fails fast instead of guessing.

Distilled from 94 documented records across 24 repositories.

Background

SyntaxError originates in the language runtimes: JavaScript's interpreter and Python's compile() raise it when source text violates the grammar, and both expose it as a catchable class. Libraries across ecosystems borrow that class for their own front doors — the parsers that turn raw text into structure before any logic runs. The records span template parsing (Twig's token parser for {% trans %}), embedded expression languages (pandas eval/query walking the Python AST, pytest's marker-expression tokenizer for -m, CPython's ForwardRef compiling annotation strings with compile(..., 'eval')), wire-protocol headers (the Sec-WebSocket-Extensions and Sec-WebSocket-Protocol parsers in ws), configuration grammars (pip's PEP 508 parse_requirement, ultralytics' check_dict_alignment against default.yaml, the CSS worker's at-rule parser in dianping/cat), and code analysis (Acorn inside Hoppscotch's script sandbox, Vite's analyzeImportedModDifference for SSR imports). In every case the meaning is the same: the input stopped being interpretable at the grammar layer, before semantics or execution began.,From the caller's side the family has a consistent shape: a message naming what was expected or what was found, plus a position — line and column for the CSS worker and Twig, a byte offset for ws's 'Unexpected character at index', a span for swc's XML parser, a column for pytest's quote errors. That position marks where the parser noticed, not necessarily what caused the drift: an unmatched brace earlier in a stylesheet can surface as 'Unexpected token' much later, and pip's 'unexpected trailing data' names residue that survives after an otherwise complete requirement. Messages can also be borrowed misleadingly: swc's XML parser reports phase errors with JavaScript-flavored wording ('The requested module ... does not provide an export named', 'Cannot use import.meta outside a module') that describe parser phases, not modules. Whether the error is fatal is library-specific: dianping/cat's CSS parser downgrades it to an 'error' event in non-strict mode and keeps parsing, swc's XML parser collects errors in a vector and still returns a Document (one with no root element), while Vite's SSR guard and Twig's token parsers abort immediately.,Much of the family is not literal tokenizing failure but the library's way of saying the input cannot be interpreted as written. ultralytics raises SyntaxError for an unknown config key and appends difflib close-match suggestions; symfony raises it for a Twig filter whose providing component is not installed and answers with a 'composer require' suggestion; Pathway raises it for correlated subqueries its SQL engine cannot resolve; vitest raises it for expect.poll() combined with snapshot or throw matchers; pandas raises it for an '@' prefix at top-level eval where no local scope exists. Import analysis sits in between: Vite statically checks named imports against what a CommonJS module's module.exports exposes and emulates Node's own 'Named export not found' error, while Hoppscotch rejects import bindings that collide with sandbox-reserved names or that resolve to two different sources across combined scripts. None of these involve a broken tokenizer — the grammar being enforced is the library's contract about shape, order, and names, so the fix is usually to change the input or the call, not to catch harder.

Common causes

What usually fixes it

Go deeper

Documented occurrences

…and 74 more across the corpus — use search.

Honest provenance: generated on 2026-08-18 from AI-assisted analysis of the linked records. See how records are made.