facebook/flow · error · Error
Cannot insert array into non-array parent type: ${parent.typ
Error message
Cannot insert array into non-array parent type: ${parent.type} What it means
When replaceNodeOnParent resolves where the original node lives, a 'single' result means the node is stored as a lone value under a parent key (e.g. IfStatement.consequent, VariableDeclarator.init), not inside an array. Such a slot can hold exactly one node, so when the replacement value is an array of nodes there is nowhere to put the extra nodes and this error is thrown rather than silently dropping them.
Source
Thrown at packages/flow-parser/oxidized-src/transform/astNodeMutationHelpers.js:105
const replacementParent = getParentKey(
originalNode,
originalNodeParent,
visitorKeys,
);
const parent = replacementParent.node;
if (replacementParent.type === 'array') {
// $FlowExpectedError[prop-missing]
parent[replacementParent.key] = replaceInArray(
// $FlowExpectedError[prop-missing]
parent[replacementParent.key],
replacementParent.targetIndex,
Array.isArray(nodeToReplaceWith)
? nodeToReplaceWith
: [nodeToReplaceWith],
);
} else {
if (Array.isArray(nodeToReplaceWith)) {
throw new Error(
`Cannot insert array into non-array parent type: ${parent.type}`,
);
}
// $FlowExpectedError[prop-missing]
parent[replacementParent.key] = nodeToReplaceWith;
}
}
/**
* Remove a node from the AST its connected to (via the parent pointer).
*/
export function removeNodeOnParent(
originalNode: ESNode,
originalNodeParent: ESNode,
visitorKeys?: ?VisitorKeysType,
): void {
const replacementParent = getParentKey(
originalNode,View on GitHub (pinned to d1341dac89)
Solutions
- Return a single wrapping node instead, classically a BlockStatement for statement positions
- Only return arrays for nodes you know sit inside an array key such as Program.body or BlockStatement.body
- Check the node's parent key before choosing single vs array replacement
Example fix
// before
if (x) return [assignStmt, returnStmt]; // array for consequent -> throws
// after
if (x) {
return {type: 'BlockStatement', body: [assignStmt, returnStmt]};
} Defensive patterns
Strategy: type-guard
Validate before calling
const SINGLE_KEYS = new Set(['consequent', 'alternate', 'test', 'init', 'argument', 'discriminant']);
function canReturnArray(parent, key) {
return Array.isArray(parent[key]); // only array slots accept array results
} Type guard
// array replacement is safe only if the slot currently holds an array
const slotIsArray = (parent, key) => Array.isArray(parent[key]);
// visitor: return Array.isArray(result) && !slotIsArray(parent, key)
// ? {type: 'BlockStatement', body: result}
// : result; Try / catch
try {
SimpleTransform.transform(ast, options);
} catch (e) {
if (e.message.includes('Cannot insert array into non-array parent')) {
throw new Error('Wrap multi-node results in a BlockStatement for single-node slots');
}
throw e;
} Prevention
- Check Array.isArray(parent[key]) before returning an array from a visitor
- Default to wrapping multi-statement results in a BlockStatement for statement slots
- Save array returns for slots you know are arrays (body, params, arguments, elements, properties)
When it happens
Trigger: A visitor returns an array of nodes (a 'replace with many' result) for a node that occupies a singular position: the non-block consequent or alternate of an if, a declarator's init, the body statement of a block-less loop, a return argument.
Common situations: Codemods that expand one statement into several (e.g. injecting assignments before an expression) applied to if-branches written without braces; generic 'expand' visitors that always return arrays.
Related errors
- SimpleTransform: invalid array result for root node
- 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
- No visitor keys found for node type "${node.type}".
AI-assisted analysis of facebook/flow@d1341dac89 (2026-08-17).
Data as JSON: /api/errors/7c798af046e16c52.
Report an issue: GitHub.