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

  1. Make the visitor return a single node for the root type (usually the Program itself)
  2. If you need many top-level statements, return a single Program with a new body array instead of returning the array
  3. 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

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


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