{"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/d1341dac899a79c027762f6b423d896045287620/packages/flow-transform/src/traverse/NodeEventGenerator.js#L60-L96","documentation":"getPossibleTypes() in NodeEventGenerator resolves an identifier-style selector (a bare node-type name such as 'CallExpression') against FlowVisitorKeys; if the name is not a key in that table it throws. In practice the selector comes from the event names your visitor registers, i.e. a visitor key like visitFooBar becomes the selector 'FooBar'. The error therefore means you registered a visitor for a node type that does not exist in the Flow AST vocabulary — usually a TypeScript/Babel-only type or a typo.","triggerScenarios":"Defining a visitor with a key for a non-Flow node type, e.g. visitTSTypeAnnotation() or visitClassPrivateProperty(), which parses to identifier selector 'TSTypeAnnotation' that is absent from FlowVisitorKeys; misspelling a real type such as visitCallExpresion(); using a selector like 'StringLiteral' (Babel naming) instead of Flow's 'Literal'.","commonSituations":"Porting an ESLint/Babel codemod to flow-transform and keeping TS/Babel type names; renaming refactors that break a visitor key; copy-pasting selectors from documentation for a different parser.","solutions":["Use exact Flow AST node type names (see flow-ast's FlowVisitorKeys), e.g. visitTSTypeAnnotation -> visitTypeCastExpression or the Flow equivalent; StringLiteral -> Literal.","Validate each visitor key's node type against FlowVisitorKeys before registering the visitor.","For misspellings, cross-check the name against the Flow parser output (Object.keys on a parsed node's types).","If you need TypeScript AST support, use a TS-aware toolchain instead of flow-transform."],"exampleFix":"// before\nconst visitor = {\n  visitTSTypeAnnotation(node) {}, // 'TSTypeAnnotation' not in FlowVisitorKeys\n};\n\n// after\nconst visitor = {\n  visitTypeAnnotation(node) {}, // Flow AST type name\n};","handlingStrategy":"type-guard","validationCode":"import {FlowVisitorKeys} from 'flow-ast';\n\nfunction validateVisitorKeys(visitor) {\n  const invalid = Object.keys(visitor)\n    .filter(k => k.startsWith('visit'))\n    .map(k => k.slice('visit'.length))\n    .filter(type => !(type in FlowVisitorKeys));\n  if (invalid.length > 0) {\n    throw new Error(`Unknown Flow node types in visitor: ${invalid.join(', ')}`);\n  }\n}","typeGuard":"/** True when `type` is a real Flow AST node type usable as a visitor selector. */\nimport {FlowVisitorKeys} from 'flow-ast';\n\nfunction isFlowNodeType(type) {\n  return typeof type === 'string' && type in FlowVisitorKeys;\n}","tryCatchPattern":"try {\n  traverse(ast, visitor);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Unexpected selector')) {\n    // a visitor key names a non-Flow node type; fix the key names\n    console.error('bad visitor key, not a Flow node type:', err.message);\n  } else {\n    throw err;\n  }\n}","preventionTips":["Run validateVisitorKeys(visitor) at startup in development builds.","Keep a cheat-sheet of Flow type names (Literal vs StringLiteral, no TS* types) when porting from Babel/ESLint.","Enable Flow type checking on codemod sources so misspelled visit keys surface."],"tags":["flow-transform","traverse","selector","visitor-keys","typo"],"backgroundTag":"unknown-ast-node-type","analyzedSha":"d1341dac899a79c027762f6b423d896045287620","analyzedAt":"2026-08-17T00:07:02.212Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}