facebook/flow · error

Cannot insert array into non-array parent type

Error message

Cannot insert array into non-array parent type: ${parent.type}

What it means

replaceNodeOnParent accepts either a single node or an array of nodes, but an array is only valid when the located parent slot is itself an array property (replacementParent.type === 'array'). Replacing a single-node slot (e.g. `argument`, `body`, `init`) with multiple nodes has no valid representation, so it throws naming the parent type.

Solutions

  1. Insert multiple nodes into an array slot instead: find the enclosing array (e.g. program/body or block.body) and use the array-based mutation path with the correct index.
  2. If you must keep the slot, wrap the multiple nodes in a single container node (e.g. a SequenceExpression or a Block) as appropriate for the grammar.
  3. Pass a single node when the target slot is single-valued.

Example fix

// before
replaceNodeOnParent(stmt, [decl, call]); // stmt sits in body[i] via single key -> throws

// after
const body = program.body;
const idx = body.indexOf(stmt);
replaceInArray(body, idx, [decl, call]); // array slot supports multiple nodes
Defensive patterns

Strategy: validation

Validate before calling

// Verify the target slot is an array before replacing with many nodes
function canReplaceWithMany(target) {
  const parent = target.parent;
  return Object.keys(parent).some((k) => Array.isArray(parent[k]) && parent[k].includes(target));
}

Type guard

function isInArraySlot(target) {
  const parent = target.parent;
  if (parent == null) return false;
  return Object.keys(parent).some((k) => Array.isArray(parent[k]) && parent[k].includes(target));
}

Prevention

When it happens

Trigger: Calling replaceNodeOnParent(node, [a, b]) where node sits in a single-node position such as an expression's argument, a declaration's init, or a function's id — anywhere the visitor key holds one node rather than an array.

Common situations: Codemods that expand one statement/expression into several (e.g. splitting an expression into multiple statements) without moving to a statement-list slot; generic 'replace with list' helpers applied to arbitrary nodes.

Related errors


AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20). Data as JSON: /api/errors/7c798af046e16c52. Report an issue: GitHub.

Appendix: 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 f88ac94bcf)