facebook/flow · error · Error
SimpleTransform: invalid array result for root node
Error message
SimpleTransform: invalid array result for root node
What it means
SimpleTransform applies your visitor bottom-up and, for every node, either removes it (null result), replaces it on its parent, or splices an array result into the parent's array-valued key. The root node passed to transform() has no parent, so there is nothing to splice an array into; when the visitor's result for the root node is an array, this error is thrown. It guards the invariant that the AST always has exactly one root.
Source
Thrown at packages/flow-parser/oxidized-src/transform/SimpleTransform.js:103
setParentPointer(resultNode, parent);
if (Array.isArray(resultNode)) {
traversedResultNode = resultNode
.map(item => this.transform(item, options))
.filter(item => item != null);
} else {
traversedResultNode = this.transform(resultNode, options);
}
}
if (parent == null) {
if (node !== rootNode) {
throw new Error(
'SimpleTransform infra error: Parent not set on non root node, this should not be possible',
);
}
if (Array.isArray(traversedResultNode)) {
throw new Error(
'SimpleTransform: invalid array result for root node',
);
} else {
resultRootNode = traversedResultNode;
}
} else if (traversedResultNode == null) {
removeNodeOnParent(node, parent, options.visitorKeys);
} else {
replaceNodeOnParent(
node,
parent,
traversedResultNode,
options.visitorKeys,
);
setParentPointer(traversedResultNode, parent);
}
throw SimpleTraverser.Skip;View on GitHub (pinned to d1341dac89)
Solutions
- Make the visitor return a single node for the root type (usually the Program itself)
- If you need many top-level statements, return a single Program with a new body array instead of returning the array
- Only return arrays for nodes you know are stored inside a parent's array key (e.g. statements in Program.body)
Example fix
// before
visitor.transform = (node) => {
if (node.type === 'Program') return node.body; // array -> throws
}
// after
visitor.transform = (node) => {
if (node.type === 'Program') {
return {...node, body: newBody}; // single node
}
} Defensive patterns
Strategy: type-guard
Type guard
// inside your visitor, before returning for the root type
const isRoot = (node, rootNode) => node === rootNode;
const safeResult = (node, rootNode, result) =>
isRoot(node, rootNode) && Array.isArray(result)
? result.find(n => n != null) || result[0]
: result; Try / catch
try {
out = SimpleTransform.transform(root, {visitor});
} catch (e) {
if (e.message.includes('invalid array result for root node')) {
throw new Error('Visitor must return a single node for the root; put extras in Program.body');
}
throw e;
} Prevention
- Write the Program/root visitor case first and make it return exactly one node
- Reserve array returns for nodes you have verified sit inside a parent's array key
- Unit-test visitors against a minimal Program fixture before running on real code
When it happens
Trigger: A visitor whose transform case for the root node type (normally 'Program') returns an array, e.g. return [nodeA, nodeB], or a 'replace with many' helper result applied to the Program node itself.
Common situations: Writing one generic visitor that returns arrays for every statement-like node and forgetting to special-case Program; codemods converted from tools where returning arrays at the root is allowed; unit tests that pass a non-Program root and return arrays.
Related errors
- SimpleTransform.transformProgram: Expected program node.
- Expected parent node to be set on "${target.type}"
- Expected to find the ${target.type} as a direct child of the
- Cannot insert array into non-array parent type: ${parent.typ
- No visitor keys found for node type "${node.type}".
AI-assisted analysis of facebook/flow@d1341dac89 (2026-08-17).
Data as JSON: /api/errors/ab266343c4f0f71c.
Report an issue: GitHub.