facebook/flow · error
SimpleTransform: invalid array result for root node
Error message
SimpleTransform: invalid array result for root node
What it means
SimpleTransform walks the AST and, when it reaches the rootNode with no parent, must assign exactly one node as the transformed root. If the visitor's result for the root node is an array (multiple replacement nodes), there is nowhere to splice them — a Program root cannot be replaced by several nodes — so it throws this invariant error.
Solutions
- Special-case the root in your visitor: if (node.type === 'Program') return programWithNewBody(node, nodes) — a single Program node containing the changes.
- Return a single replacement node for the root; never an array.
- Do multi-node insertion into an array slot (e.g. node.body of the Program) instead of replacing the root.
Example fix
// before
transform(node) {
if (node.type === 'Program') return node.body.map(f); // array for root -> throws
}
// after
transform(node) {
if (node.type === 'Program') return SimpleTransform.nodeWith(node, {body: node.body.map(f)});
} Defensive patterns
Strategy: validation
Validate before calling
// Guard the root in your visitor before running the transform
function rootSafeTransform(program, transform) {
return SimpleTransform.transformProgram(program, {
transform(node) {
const result = transform(node);
if (node.type === 'Program' && Array.isArray(result)) {
throw new TypeError('visitor returned multiple nodes for Program root');
}
return result;
},
});
} Type guard
function isSingleNode(v) {
return v != null && typeof v === 'object' && typeof v.type === 'string' && !Array.isArray(v);
} Prevention
- Always special-case Program in visitors that may return arrays.
- Put multi-node results into array slots like Program.body, never at the root.
When it happens
Trigger: Calling SimpleTransform.transform(program, {transform}) where the transform callback returns an array for the Program node itself (or for whatever node you passed as root). Returning arrays is legal only for nodes whose parent slot is an array (e.g. statements inside body).
Common situations: Custom transforms designed to expand one statement into several that accidentally also fire on the root; copy-pasted visitors from array-mutation helpers; passing a non-Program root and returning multiple nodes for it.
Related errors
- SimpleTransform.transformProgram: Expected program node.
- Cannot insert array into non-array parent type
- Expected parent node to be set on
- flowImportTo: Unexpected transform result.
- Invalid Mutation: Tried to mutate an elements array with an…
AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20).
Data as JSON: /api/errors/ab266343c4f0f71c.
Report an issue: GitHub.
Appendix: 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 f88ac94bcf)