facebook/flow · error
No visitor keys found for node type
Error message
No visitor keys found for node type "${node.type}". What it means
getVisitorKeys returns the traversal keys for a node type from the supplied visitorKeys map or the default FlowVisitorKeys. A node whose type string has no entry means the traverser/transformer does not know that AST dialect's shape, so it throws rather than silently skipping children.
Solutions
- Pass the matching visitorKeys option: getVisitorKeys(node, myVisitorKeys) / SimpleTransform with visitorKeys covering your AST's node types.
- Use parser/traverse/transform helpers from the same package that produced the AST.
- Align versions: upgrade flow-parser so its FlowVisitorKeys include the node type named in the message.
- For custom node types, extend the visitor keys map with entries for them before traversal.
Example fix
// before
const ast = tsParse(code); // TSESTree nodes
SimpleTransform.transformProgram(ast, {transform}); // no visitorKeys -> throws on TS* nodes
// after
import {visitorKeys as tsVisitorKeys} from './tsVisitorKeys.js';
SimpleTransform.transformProgram(tsAst, {transform, visitorKeys: {...FlowVisitorKeys, ...tsVisitorKeys}}); Defensive patterns
Strategy: type-guard
Validate before calling
// Verify coverage before traversing
import {visitorKeys as FlowVisitorKeys} from 'flow-parser';
function astTypesCovered(ast, extra = {}) {
const keys = {...FlowVisitorKeys, ...extra};
const missing = new Set();
(function walk(n) {
if (n == null || typeof n !== 'object') return;
if (typeof n.type === 'string' && keys[n.type] == null) missing.add(n.type);
for (const v of Object.values(n)) { if (Array.isArray(v)) v.forEach(walk); else walk(v); }
})(ast);
return {ok: missing.size === 0, missing: [...missing]};
} Type guard
import {visitorKeys as FlowVisitorKeys} from 'flow-parser';
function hasVisitorKeys(node, visitorKeys) {
return (visitorKeys ?? FlowVisitorKeys)[node.type] != null;
} Prevention
- Pass visitorKeys matching the AST dialect whenever transforming non-Flow ASTs.
- Use parse/traverse/transform from the same package version as the AST producer.
- On parser upgrades, watch release notes for new node types and re-check coverage.
When it happens
Trigger: Traversing or SimpleTransform-ing an AST containing node types absent from Flow's visitor keys: TypeScript AST nodes from typescript-estree, Babel-flavored nodes, custom/invented node types, or future Flow node types when using an older parser package.
Common situations: Mixing parsers in one pipeline (parse with TS parser, transform with flow-parser helpers); version skew where a newer parser emits a node type the installed flow-parser's visitor keys lack; hand-crafted ASTs for testing.
Related errors
- Cannot insert array into non-array parent type
- Expected parent node to be set on
- Invalid Mutation: Tried to mutate an elements array with an…
- SimpleTransform: invalid array result for root node
- SimpleTransform.transformProgram: Expected program node.
AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20).
Data as JSON: /api/errors/bf6df1fe354931bd.
Report an issue: GitHub.
Appendix: 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 f88ac94bcf)