{"record":{"id":"f9257342882a0f58","repo":"facebook/flow","slug":"import-export-cannot-be-inserted-into-a-insertio","errorCode":null,"errorMessage":"import/export cannot be inserted into a ${insertionParent.parent.type}.","messagePattern":"import/export cannot be inserted into a (.+?)\\.","errorType":"validation","errorClass":"InvalidInsertionError","httpStatus":null,"severity":"error","filePath":"packages/flow-transform/src/transform/mutations/InsertStatement.js","lineNumber":63,"sourceCode":"export function performInsertStatementMutation(\n  mutationContext: MutationContext,\n  mutation: InsertStatementMutation,\n): ESNode {\n  mutationContext.assertNotDeleted(\n    mutation.target,\n    `Attempted to insert ${mutation.side} a deleted ${mutation.target.type} node. This likely means that you attempted to mutate around the target after it was deleted/replaced.`,\n  );\n\n  const insertionParent = getStatementParent(mutation.target);\n\n  // enforce that if we are inserting module declarations - they are being inserted in a valid location\n  if (\n    !isValidModuleDeclarationParent(\n      insertionParent.parent,\n      mutation.nodesToInsert,\n    )\n  ) {\n    throw new InvalidInsertionError(\n      `import/export cannot be inserted into a ${insertionParent.parent.type}.`,\n    );\n  }\n\n  mutationContext.markMutation(insertionParent.parent, insertionParent.key);\n\n  if (insertionParent.type === 'array') {\n    const parent: interface {\n      [string]: ReadonlyArray<DetachedNode<Statement | ModuleDeclaration>>,\n    } = insertionParent.parent;\n    switch (mutation.side) {\n      case 'before': {\n        parent[insertionParent.key] = astArrayMutationHelpers.insertInArray(\n          parent[insertionParent.key],\n          insertionParent.targetIndex,\n          mutation.nodesToInsert,\n        );\n        break;","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/packages/flow-transform/src/transform/mutations/InsertStatement.js#L45-L81","documentation":"InvalidInsertionError thrown by flow-transform's insertStatement mutation when the nodes being inserted include an import/export (any ModuleDeclaration) but the insertion location cannot legally hold module declarations. `isValidModuleDeclarationParent` only accepts `Program` or a `BlockStatement` whose parent is a `DeclareModule`; anything else (function BlockStatement, SwitchCase consequent, IfStatement branch) is rejected.","triggerScenarios":"`mutate.insertStatementBefore(anchor, detachedNode<ImportDeclaration>())` where `anchor.parent` is a BlockStatement inside a function, a SwitchCase, or an IfStatement branch - i.e. the anchor statement is not at the top level of the file. Same for inserting ExportNamedDeclaration anywhere but Program level.","commonSituations":"Codemods that add imports: matching a usage deep in the file (a call inside a function) and inserting the import next to it instead of hoisting to the top; transforming CommonJS requires inside nested scopes.","solutions":["Anchor import insertions to a top-level statement: walk up `anchor.parent` until `parent.type === 'Program'` and insert relative to a Program.body statement (e.g. the first existing import).","If the file has no imports, capture the first `Program.body` statement during a `Program` visit and use it as the anchor.","Only insert non-module statements relative to nested anchors.","For `declare module` blocks, a BlockStatement under DeclareModule is also legal."],"exampleFix":"// before - anchor is nested inside a function\nmutate.insertStatementBefore(usageStatement, buildImport()); // throws\n\n// after - hoist the anchor to the top level\nconst topLevel = usageStatement.parent.type === 'Program'\n  ? usageStatement\n  : /* walk up to a Program.body statement */ firstProgramStatement;\nmutate.insertStatementBefore(topLevel, buildImport());","handlingStrategy":"type-guard","validationCode":"function canHoldModuleDeclarations(anchor) {\n  const p = anchor.parent;\n  return p.type === 'Program' ||\n    (p.type === 'BlockStatement' && p.parent?.type === 'DeclareModule');\n}\n\nfunction insertImport(mutate, anchor, importNode) {\n  if (!canHoldModuleDeclarations(anchor)) {\n    // hoist: find a Program.body statement instead\n    let top = anchor;\n    while (top.parent.type !== 'Program') top = top.parent;\n    anchor = top;\n  }\n  mutate.insertStatementBefore(anchor, importNode);\n}","typeGuard":"function isModuleDeclarationAnchor(anchor /*: Statement */): boolean {\n  const p = anchor.parent;\n  return p.type === 'Program' ||\n    (p.type === 'BlockStatement' && p.parent?.type === 'DeclareModule');\n}","tryCatchPattern":"try {\n  transform(code, visitors);\n} catch (e) {\n  if (e.name === 'InvalidInsertionError' && /import\\/export/.test(e.message)) {\n    // re-anchor the insertion to a Program.body statement\n  }\n  throw e;\n}","preventionTips":["Always insert imports relative to a top-level (Program.body) statement.","Capture a Program-level anchor early (e.g. first import) during the Program visit.","Nested anchors are only for non-module statements."],"tags":["flow","flow-transform","codemod","imports","module-declaration","ast-mutation"],"backgroundTag":"invalid-ast-mutation","analyzedSha":"f88ac94bcf6992f5d5a158854d94613ebb92c6e6","analyzedAt":"2026-08-20T10:41:37.992Z","contentChangedAt":"2026-08-20T10:41:37.992Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}