facebook/flow · error · Error

No visitor keys found for node type "${node.type}".

Error message

No visitor keys found for node type "${node.type}".

What it means

getVisitorKeys is the single lookup every traversal and transform uses to enumerate a node's child keys; it indexes the visitor-keys map by node.type and throws when there is no entry. The default map is FlowVisitorKeys, which knows exactly the node types flow-parser emits (including Flow type nodes). An unknown type therefore means the AST was not produced by flow-parser, or contains injected or custom nodes.

Source

Thrown at packages/flow-parser/oxidized-src/traverse/getVisitorKeys.js:31

import type {ESNode} from 'flow-estree';
import type {VisitorKeys as VisitorKeysType} from '../generated/ESTreeVisitorKeys';

import FlowVisitorKeys from '../generated/ESTreeVisitorKeys';

export function isNode(thing: unknown) /*: implies thing is {readonly [string]: unknown} */ {
  return (
    typeof thing === 'object' && thing != null && typeof thing.type === 'string'
  );
}

export type {VisitorKeysType};
export function getVisitorKeys<T extends ESNode>(
  node: T,
  visitorKeys?: ?VisitorKeysType,
) /*: ReadonlyArray<keyof T> */ {
  const keys = (visitorKeys ?? FlowVisitorKeys)[node.type];
  if (keys == null) {
    throw new Error(`No visitor keys found for node type "${node.type}".`);
  }

  // $FlowExpectedError[prop-missing]
  return keys;
}

View on GitHub (pinned to d1341dac89)

Solutions

  1. Only traverse ASTs produced by the same flow-parser version
  2. Pass a custom visitorKeys map via the traversal or transform options that covers your AST dialect's node types
  3. Upgrade flow-parser so FlowVisitorKeys includes the newest node types it emits

Example fix

// before
traverse(babelAst, visitor); // 'File'/'TS*' types unknown -> throws

// after
const flowAst = require('flow-parser').parse(source, {});
traverse(flowAst, visitor);
Defensive patterns

Strategy: validation

Validate before calling

import {FlowVisitorKeys} from 'flow-parser'; // or the traverse export your version ships
function assertKnownTypes(ast) {
  const stack = [ast];
  while (stack.length) {
    const n = stack.pop();
    if (!(n.type in FlowVisitorKeys)) {
      throw new Error("AST contains non-Flow node type '" + n.type + "'; reparse with flow-parser");
    }
    for (const k of FlowVisitorKeys[n.type]) {
      const v = n[k];
      if (v && typeof v.type === 'string') stack.push(v);
      else if (Array.isArray(v)) for (const c of v) if (c && typeof c.type === 'string') stack.push(c);
    }
  }
}

Type guard

const isKnownNodeType = (type, visitorKeys) => type in (visitorKeys || FlowVisitorKeys);

Try / catch

try {
  traverse(ast, visitor);
} catch (e) {
  if (e.message.startsWith('No visitor keys found')) {
    throw new Error('AST dialect mismatch: pass a matching visitorKeys option or reparse with flow-parser');
  }
  throw e;
}

Prevention

When it happens

Trigger: Feeding an AST from another parser (Babel, Acorn, espree, typescript-eslint) into flow-parser's traverse or SimpleTransform: node types like 'File', 'TSUnionType', 'ChainExpression' have no FlowVisitorKeys entry; injecting custom node types from a visitor; using an outdated flow-parser whose map predates a newer node type.

Common situations: Toolchains that mix parsers (lint with espree, transform with flow-parser) and pass ASTs between them; codemods run on TypeScript-in-Flow repos; upgrading one tool but not flow-parser.

Related errors


AI-assisted analysis of facebook/flow@d1341dac89 (2026-08-17). Data as JSON: /api/errors/bf6df1fe354931bd. Report an issue: GitHub.