{"record":{"id":"007c99fe670ffe1a","repo":"facebook/flow","slug":"tried-to-remove-node-type-from-parent-of-type","errorCode":null,"errorMessage":"Tried to remove ${node.type} from parent of type ${node.parent.type}.\nHowever ${node.type} can only be safely removed from parent of type ${expectedParents.join(' | ')}.","messagePattern":"Tried to remove (.+?) from parent of type (.+?)\\.\nHowever (.+?) can only be safely removed from parent of type (.+?)\\.","errorType":"validation","errorClass":"InvalidRemovalError","httpStatus":null,"severity":"error","filePath":"packages/flow-transform/src/transform/mutations/RemoveNode.js","lineNumber":192,"sourceCode":"\n      case 'Property':\n        assertParent(VALID_PROPERTY_PARENTS);\n        return 'properties';\n\n      // Identifier can be the child of a number of usecases\n      case 'Identifier':\n        switch (node.parent.type) {\n          case 'ArrowFunctionExpression':\n          case 'FunctionDeclaration':\n          case 'FunctionExpression':\n            return 'params';\n\n          case 'ArrayExpression':\n          case 'ArrayPattern':\n            return 'elements';\n\n          default:\n            throw new InvalidRemovalError(\n              getErrorMessage([\n                'ArrowFunctionExpression',\n                'FunctionDeclaration',\n                'FunctionExpression',\n                'ArrayExpression',\n                'ArrayPattern',\n              ]),\n            );\n        }\n\n      // RestElement can be the child of a number of usecases\n      case 'RestElement':\n        switch (node.parent.type) {\n          case 'ArrowFunctionExpression':\n          case 'FunctionDeclaration':\n          case 'FunctionExpression':\n          case 'ComponentDeclaration':\n            return 'params';","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/packages/flow-transform/src/transform/mutations/RemoveNode.js#L174-L210","documentation":"InvalidRemovalError thrown by flow-transform's removeNode when deleting an `Identifier` whose parent is not in the supported list. Identifiers can only be removed from `params` of ArrowFunctionExpression/FunctionDeclaration/FunctionExpression or `elements` of ArrayExpression/ArrayPattern; the message lists those five parents. Any other position (VariableDeclarator.id, Property.key/value, MemberExpression.property, callee, JSX containers) is rejected because removing it would leave invalid syntax.","triggerScenarios":"`mutate.removeNode(identifierNode)` where the identifier is a variable name in `const x = ...` (parent VariableDeclarator), an object property key, a member-expression property, or a function callee.","commonSituations":"Rename/delete-variable codemods that try to remove the Identifier instead of the enclosing VariableDeclarator or Property; deleting a binding parameter that is actually an AssignmentPattern (whose removal is handled separately).","solutions":["Check `node.parent.type` before calling removeNode on an Identifier.","Remove the enclosing node instead: VariableDeclarator removal for `const x = ...`, Property removal for object members.","To rename, use replaceNode on the Identifier rather than remove+insert.","For destructured params, remove the whole AssignmentPattern or its outer ArrayPattern/ObjectPattern."],"exampleFix":"// before\nmutate.removeNode(varDeclarator.id); // Identifier under VariableDeclarator - throws\n\n// after\nmutate.removeNode(varDeclarator); // removes the whole `x = init`","handlingStrategy":"type-guard","validationCode":"const IDENTIFIER_REMOVAL_PARENTS = new Set([\n  'ArrowFunctionExpression', 'FunctionDeclaration', 'FunctionExpression',\n  'ArrayExpression', 'ArrayPattern',\n]);\n\nif (node.type === 'Identifier' && IDENTIFIER_REMOVAL_PARENTS.has(node.parent.type)) {\n  mutate.removeNode(node);\n} else if (node.type === 'Identifier' && node.parent.type === 'VariableDeclarator') {\n  mutate.removeNode(node.parent); // remove the declarator instead\n}","typeGuard":"function canRemoveIdentifier(node): boolean {\n  return node.type === 'Identifier' && [\n    'ArrowFunctionExpression', 'FunctionDeclaration', 'FunctionExpression',\n    'ArrayExpression', 'ArrayPattern',\n  ].includes(node.parent.type);\n}","tryCatchPattern":"try {\n  mutate.removeNode(node);\n} catch (e) {\n  if (e.name === 'InvalidRemovalError') { /* remove an enclosing node instead */ }\n  else throw e;\n}","preventionTips":["Remove the enclosing VariableDeclarator/Property for names, not the Identifier.","Guard every removeNode(Identifier) with a parent-type check.","For renames use replaceNode rather than remove+insert."],"tags":["flow","flow-transform","codemod","remove-node","identifier","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"}