{"record":{"id":"93c8429ae2b8d3e3","repo":"facebook/flow","slug":"syntax-error-in-selector-rawselector-at-posit","errorCode":null,"errorMessage":"Syntax error in selector \"${rawSelector}\" at position ${err.location.start.offset}: ${err.message}","messagePattern":"Syntax error in selector \"(.+?)\" at position (.+?): (.+?)","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"packages/flow-transform/src/traverse/NodeEventGenerator.js","lineNumber":235,"sourceCode":"  );\n}\n\n/**\n * Parses a raw selector string, and throws a useful error if parsing fails.\n * @param rawSelector A raw AST selector\n * @returns An object (from esquery) describing the matching behavior of this selector\n * @throws An error if the selector is invalid\n */\nfunction tryParseSelector(rawSelector: string): Selector {\n  try {\n    return esquery.parse(rawSelector.replace(/:exit$/u, ''));\n  } catch (err) {\n    if (\n      err.location &&\n      err.location.start &&\n      typeof err.location.start.offset === 'number'\n    ) {\n      throw new SyntaxError(\n        `Syntax error in selector \"${rawSelector}\" at position ${err.location.start.offset}: ${err.message}`,\n      );\n    }\n    throw err;\n  }\n}\n\nconst selectorCache = new Map<string, ParsedSelector>();\n\n/**\n * Parses a raw selector string, and returns the parsed selector along with specificity and type information.\n * @param rawSelector A raw AST selector\n * @returns A selector descriptor\n */\nfunction parseSelector(rawSelector: string): ParsedSelector {\n  const cachedSelector = selectorCache.get(rawSelector);\n  if (cachedSelector) {\n    return cachedSelector;","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/facebook/flow/blob/d1341dac899a79c027762f6b423d896045287620/packages/flow-transform/src/traverse/NodeEventGenerator.js#L217-L253","documentation":"tryParseSelector() runs each selector string through esquery.parse() (after stripping a trailing :exit) and rethrows parse failures as a SyntaxError that includes the offset and the underlying esquery message. Selectors originate from the event names registered on your visitor — keys that are not visitXxx method names are treated as raw esquery strings. This error means one of those strings is not valid esquery syntax, for example an unbalanced bracket, a stray combinator, or a malformed pseudo-class.","triggerScenarios":"Adding an arbitrary string key to the visitor object such as 'CallExpression >' , '[async=true' , or ':exitt' (misspelled exit pseudo); registering selector strings with unsupported esquery features; trailing whitespace or smart quotes pasted from docs.","commonSituations":"Using advanced esquery attribute/pseudo selectors and getting the syntax slightly wrong; typos in the ':exit' suffix; keys on the visitor object that were meant as helper methods but got parsed as selectors because they do not start with 'visit'.","solutions":["Fix the selector syntax per esquery grammar (balanced brackets, valid pseudo-classes, supported combinators); keep ':exit' as the exact suffix.","Dry-run validation: call esquery.parse on each selector string during development/startup so failures surface with position before traversal.","Prefix non-selector helper properties so they are not collected as event names, or keep them off the visitor object.","Use simple type-name selectors (visitXxx) unless you need esquery complexity."],"exampleFix":"// before\nconst visitor = {\n  visitCallExpression(node) {},\n  'CallExpression > ': fn, // trailing combinator -> SyntaxError\n};\n\n// after\nconst visitor = {\n  visitCallExpression(node) {},\n  'CallExpression > MemberExpression': fn, // valid esquery\n};","handlingStrategy":"validation","validationCode":"import esquery from 'esquery';\n\nfunction validateSelectors(selectors) {\n  for (const raw of selectors) {\n    try {\n      esquery.parse(raw.replace(/:exit$/u, ''));\n    } catch {\n      throw new Error(`Invalid AST selector: ${JSON.stringify(raw)}`);\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  traverse(ast, visitor);\n} catch (err) {\n  if (err instanceof SyntaxError && err.message.includes('Syntax error in selector')) {\n    // the message names the raw selector and offset; fix or drop that selector\n    console.error(err.message);\n  } else {\n    throw err;\n  }\n}","preventionTips":["Dry-run esquery.parse on every string selector during development/startup.","Keep non-visitor helper properties off the visitor object so they are not parsed as selectors.","Prefer simple visitXxx keys; add complex esquery strings incrementally with tests."],"tags":["flow-transform","esquery","selector","syntax-error","traverse"],"backgroundTag":"invalid-selector-syntax","analyzedSha":"d1341dac899a79c027762f6b423d896045287620","analyzedAt":"2026-08-17T00:07:02.212Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}