{"record":{"id":"51c2aa16635bdfa8","repo":"facebook/flow","slug":"unexpected-selector-parsedselector-value","errorCode":null,"errorMessage":"Unexpected selector ${parsedSelector.value}","messagePattern":"Unexpected selector (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/flow-transform/src/traverse/NodeEventGenerator.js","lineNumber":78,"sourceCode":"\n  let result = [...new Set(arrays[0])];\n\n  for (const array of arrays.slice(1)) {\n    result = result.filter(x => array.includes(x));\n  }\n  return result;\n}\n\n/**\n * Gets the possible types of a selector\n * @param parsedSelector An object (from esquery) describing the matching behavior of the selector\n * @returns The node types that could possibly trigger this selector, or `null` if all node types could trigger it\n */\nfunction getPossibleTypes(parsedSelector: Selector): ?Array<ESNode['type']> {\n  switch (parsedSelector.type) {\n    case 'identifier':\n      if (!(parsedSelector.value in FlowVisitorKeys)) {\n        throw new Error(`Unexpected selector ${parsedSelector.value}`);\n      }\n      // $FlowExpectedError[incompatible-type]\n      return [parsedSelector.value];\n\n    case 'matches': {\n      const typesForComponents = parsedSelector.selectors.map(getPossibleTypes);\n      const typesForComponentsNonNull = typesForComponents.filter(Boolean);\n\n      if (typesForComponents.length === typesForComponentsNonNull.length) {\n        return union(...typesForComponentsNonNull);\n      }\n      return null;\n    }\n\n    case 'compound': {\n      const typesForComponents = parsedSelector.selectors\n        .map(getPossibleTypes)\n        .filter(Boolean);","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/packages/flow-transform/src/traverse/NodeEventGenerator.js#L60-L96","documentation":"Plain Error thrown by flow-transform's traverse when a visitor key used as an esquery identifier selector is not a known Flow AST node type (validated against `FlowVisitorKeys` from flow-parser). Bare identifiers in selectors are interpreted as node type names, so a typo or a Babel/TypeScript/ESLint-only type name fails immediately when the NodeEventGenerator registers listeners.","triggerScenarios":"`traverse(ast, {CallExpresion(node) {}})` (typo) or using Babel/TS names like `TSTypeAnnotation`, `ClassProperty`, `StringLiteral` - Flow's ESTree AST uses different names (e.g. `Literal`, `PropertyDefinition`). Thrown when traverse() builds its event generator, before any traversal.","commonSituations":"Porting ESLint rules or Babel plugin visitors to flow-transform; copying selector examples written against estree/babel node type lists; version drift where a node type was renamed in flow-estree.","solutions":["Use Flow ESTree node type names - dump the AST with hermes-parser/flow-parser to confirm exact type strings.","Map common renames: StringLiteral/NumberLiteral -> Literal, ClassProperty -> PropertyDefinition, TSTypeAnnotation -> Flow type annotation nodes.","For non-type selectors use esquery syntax that does not require an identifier (attribute selectors, `*`).","Check the name against FlowVisitorKeys (exported from flow-parser) at startup."],"exampleFix":"// before\ntraverseWithContext(code, ast, scope, () => ({}), ctx => ({\n  ClassProperty(node) {}, // not a Flow ESTree type - throws\n}));\n\n// after\ntraverseWithContext(code, ast, scope, () => ({}), ctx => ({\n  PropertyDefinition(node) {},\n}));","handlingStrategy":"validation","validationCode":"import {FlowVisitorKeys} from 'flow-parser';\n\nfunction validateVisitorKeys(selectors) {\n  for (const sel of Object.keys(selectors)) {\n    const base = sel.replace(/:exit$/u, '');\n    // bare identifiers (no combinators/attributes) must be Flow node types\n    if (/^[A-Za-z]+$/.test(base) && !(base in FlowVisitorKeys)) {\n      throw new Error(`visitor key '${sel}' is not a Flow AST node type`);\n    }\n  }\n}\n\nvalidateVisitorKeys(selectors); // before traverseWithContext(...)","typeGuard":"function isFlowNodeType(name: string): boolean {\n  const {FlowVisitorKeys} = require('flow-parser');\n  return name in FlowVisitorKeys;\n}","tryCatchPattern":null,"preventionTips":["Use flow-estree type names (Literal, PropertyDefinition), not Babel/TS ones.","Dump the AST with hermes-parser to confirm exact type strings.","Validate bare-identifier visitor keys against FlowVisitorKeys at startup or in tests."],"tags":["flow","flow-transform","esquery","selector","visitor","node-types"],"backgroundTag":"invalid-ast-selector","analyzedSha":"f88ac94bcf6992f5d5a158854d94613ebb92c6e6","analyzedAt":"2026-08-20T10:41:37.992Z","contentChangedAt":"2026-08-20T10:41:37.992Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}