{"record":{"id":"72391b272bfd0882","repo":"facebook/flow","slug":"could-not-find-target-in-array-of-node-parent-t","errorCode":null,"errorMessage":"Could not find target in array of `${node.parent.type}.${key}`.","messagePattern":"Could not find target in array of `(.+?)\\.(.+?)`\\.","errorType":"exception","errorClass":"InvalidRemovalError","httpStatus":null,"severity":"error","filePath":"packages/flow-transform/src/transform/mutations/RemoveNode.js","lineNumber":282,"sourceCode":"                'NewExpression',\n              ]),\n            );\n        }\n\n      default:\n        throw new InvalidRemovalError(\n          `Cannot perform a remove mutation on node of type ${node.type}`,\n        );\n    }\n  })();\n\n  const targetIndex = (() => {\n    // $FlowExpectedError[prop-missing]\n    const arr = node.parent[key];\n    const idx = arr.indexOf(node);\n    // $FlowFixMe[invalid-compare]\n    if (idx === -1) {\n      throw new InvalidRemovalError(\n        `Could not find target in array of \\`${node.parent.type}.${key}\\`.`,\n      );\n    }\n    return idx;\n  })();\n\n  return {\n    type: 'array',\n    parent: node.parent,\n    key,\n    targetIndex,\n  };\n}\n\nexport function performRemoveNodeMutation(\n  mutationContext: MutationContext,\n  mutation: RemoveNodeMutation,\n): ESNode {","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/facebook/flow/blob/d1341dac899a79c027762f6b423d896045287620/packages/flow-transform/src/transform/mutations/RemoveNode.js#L264-L300","documentation":"After computing which array key holds the node, RemoveNode does parent[key].indexOf(node) to find the splice index; a -1 result means the parent pointer claims a relationship the array no longer reflects, and this InvalidRemovalError is thrown. Like the 'direct child' invariants elsewhere, it indicates the AST was mutated outside the mutation API or the node is a copy whose parent points at the original array. The message includes the parent type and key to narrow the search.","triggerScenarios":"Splicing an array manually (e.g. program.body.splice(...) inside a visitor) and then calling removeNodeMutation on a node from that region; removing a cloned node whose .parent still references the original tree's parent.","commonSituations":"Mixing direct AST manipulation with the mutation API in one pass; deep-cloning subtrees but keeping inherited parent links; running a second mutation batch over a tree already mutated by raw code.","solutions":["Do all structural changes through the mutation API: never splice parent arrays by hand during a transform","Re-parse or re-traverse to get a pristine AST before each new batch of mutations","When cloning nodes, clear their parent pointers so stale links fail fast instead of mismatching"],"exampleFix":"// before\nprogram.body.splice(2, 1); // raw splice\nmutations.push(removeNode(stmt)); // stmt no longer in body -> throws\n\n// after\nmutations.push(removeNode(program.body[2])); // engine owns the splice","handlingStrategy":"try-catch","validationCode":"function isNodeInParentArray(node, key) {\n  const arr = node.parent && node.parent[key];\n  return Array.isArray(arr) && arr.indexOf(node) !== -1;\n}","typeGuard":"const isInParentArray = (node, key) =>\n  node.parent != null && Array.isArray(node.parent[key]) &&\n  node.parent[key].includes(node);","tryCatchPattern":"try {\n  mutations.push(removeNodeMutation(node));\n} catch (e) {\n  if (e.message.includes('Could not find target in array')) {\n    // stale tree: re-parse the original source and re-locate the node instead of continuing\n    throw new Error('AST out of sync with mutation API; re-parse before mutating');\n  }\n  throw e;\n}","preventionTips":["Never splice parent arrays by hand during a transform; route all structural edits through the mutation API","Clear parent pointers when cloning nodes so stale links fail loudly","Re-parse between transform passes rather than reusing a mutated tree"],"tags":["flow-transform","removal","stale-pointer","invariant"],"backgroundTag":"stale-ast-parent-pointer","analyzedSha":"d1341dac899a79c027762f6b423d896045287620","analyzedAt":"2026-08-17T00:07:02.212Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}