{"record":{"id":"ab266343c4f0f71c","repo":"facebook/flow","slug":"simpletransform-invalid-array-result-for-root-nod","errorCode":null,"errorMessage":"SimpleTransform: invalid array result for root node","messagePattern":"SimpleTransform: invalid array result for root node","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/flow-parser/oxidized-src/transform/SimpleTransform.js","lineNumber":103,"sourceCode":"            setParentPointer(resultNode, parent);\n\n            if (Array.isArray(resultNode)) {\n              traversedResultNode = resultNode\n                .map(item => this.transform(item, options))\n                .filter(item => item != null);\n            } else {\n              traversedResultNode = this.transform(resultNode, options);\n            }\n          }\n\n          if (parent == null) {\n            if (node !== rootNode) {\n              throw new Error(\n                'SimpleTransform infra error: Parent not set on non root node, this should not be possible',\n              );\n            }\n            if (Array.isArray(traversedResultNode)) {\n              throw new Error(\n                'SimpleTransform: invalid array result for root node',\n              );\n            } else {\n              resultRootNode = traversedResultNode;\n            }\n          } else if (traversedResultNode == null) {\n            removeNodeOnParent(node, parent, options.visitorKeys);\n          } else {\n            replaceNodeOnParent(\n              node,\n              parent,\n              traversedResultNode,\n              options.visitorKeys,\n            );\n            setParentPointer(traversedResultNode, parent);\n          }\n\n          throw SimpleTraverser.Skip;","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/facebook/flow/blob/d1341dac899a79c027762f6b423d896045287620/packages/flow-parser/oxidized-src/transform/SimpleTransform.js#L85-L121","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)"],"exampleFix":"// before\nvisitor.transform = (node) => {\n  if (node.type === 'Program') return node.body; // array -> throws\n}\n\n// after\nvisitor.transform = (node) => {\n  if (node.type === 'Program') {\n    return {...node, body: newBody}; // single node\n  }\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// inside your visitor, before returning for the root type\nconst isRoot = (node, rootNode) => node === rootNode;\nconst safeResult = (node, rootNode, result) =>\n  isRoot(node, rootNode) && Array.isArray(result)\n    ? result.find(n => n != null) || result[0]\n    : result;","tryCatchPattern":"try {\n  out = SimpleTransform.transform(root, {visitor});\n} catch (e) {\n  if (e.message.includes('invalid array result for root node')) {\n    throw new Error('Visitor must return a single node for the root; put extras in Program.body');\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["ast","transform","visitor","flow-parser"],"backgroundTag":"invalid-visitor-return-value","analyzedSha":"d1341dac899a79c027762f6b423d896045287620","analyzedAt":"2026-08-17T00:07:02.212Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}