{"record":{"id":"3add287daa726148","repo":"facebook/flow","slug":"cannot-perform-a-remove-mutation-on-node-of-type","errorCode":null,"errorMessage":"Cannot perform a remove mutation on node of type ${node.type}","messagePattern":"Cannot perform a remove mutation on node of type (.+?)","errorType":"validation","errorClass":"InvalidRemovalError","httpStatus":null,"severity":"error","filePath":"packages/flow-transform/src/transform/mutations/RemoveNode.js","lineNumber":270,"sourceCode":"          case 'OptionalCallExpression':\n          case 'CallExpression':\n          case 'NewExpression':\n            return 'arguments';\n\n          default:\n            throw new InvalidRemovalError(\n              getErrorMessage([\n                'ArrayExpression',\n                'ObjectExpression',\n                'CallExpression',\n                'OptionalCallExpression',\n                '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","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/packages/flow-transform/src/transform/mutations/RemoveNode.js#L252-L288","documentation":"InvalidRemovalError thrown by removeNode's `getRemovalParent` when the node's type is not in the hardcoded whitelist of removable types (class members, enum members, component params, function params, object-type members, Property, ImportDeclaration, JSXAttribute, FunctionTypeParam, Identifier, RestElement, SpreadElement, etc.). Statements like ExpressionStatement, VariableDeclaration, or literals cannot be removed with removeNode.","triggerScenarios":"`mutate.removeNode(node)` where node is an ExpressionStatement, CallExpression, Literal, VariableDeclaration, or any type not handled by the switch in RemoveNode.js - the default branch throws immediately with the node's type.","commonSituations":"Trying to delete a whole statement or expression directly; the most common codemod mistake when removing a call statement instead of the enclosing statement.","solutions":["To delete a statement, use `mutate.replaceStatementWithMany(stmt, [])` instead of removeNode.","Remove an ancestor that is whitelisted: e.g. remove the Property for an object member, the VariableDeclarator's Property/parent for declarations, or an ImportDeclaration (which IS supported under Program).","Check RemoveNode.js's switch statement for the current whitelist before choosing the node to remove."],"exampleFix":"// before\nmutate.removeNode(exprStatement); // 'Cannot perform a remove mutation on node of type ExpressionStatement'\n\n// after\nmutate.replaceStatementWithMany(exprStatement, []);","handlingStrategy":"type-guard","validationCode":"const REMOVABLE_TYPES = new Set([\n  'PropertyDefinition', 'MethodDefinition',\n  'EnumBooleanMember', 'EnumDefaultedMember', 'EnumNumberMember', 'EnumStringMember',\n  'ComponentParameter', 'ComponentTypeParameter',\n  'AssignmentPattern', 'ArrayPattern', 'ObjectPattern', 'FunctionTypeParam',\n  'JSXAttribute', 'ImportDeclaration',\n  'ObjectTypeCallProperty', 'ObjectTypeIndexer', 'ObjectTypeInternalSlot',\n  'ObjectTypeProperty', 'ObjectTypeSpreadProperty', 'Property',\n  'Identifier', 'RestElement', 'SpreadElement',\n]);\n\nif (REMOVABLE_TYPES.has(node.type)) {\n  mutate.removeNode(node);\n} else {\n  mutate.replaceStatementWithMany(node, []); // statements: replace with nothing\n}","typeGuard":"function canRemoveNode(node): boolean {\n  return new Set([\n    'PropertyDefinition', 'MethodDefinition', 'Property', 'JSXAttribute',\n    'ImportDeclaration', 'Identifier', 'RestElement', 'SpreadElement',\n    'AssignmentPattern', 'ArrayPattern', 'ObjectPattern', 'FunctionTypeParam',\n    'ComponentParameter', 'ComponentTypeParameter',\n    'EnumBooleanMember', 'EnumDefaultedMember', 'EnumNumberMember', 'EnumStringMember',\n    'ObjectTypeCallProperty', 'ObjectTypeIndexer', 'ObjectTypeInternalSlot',\n    'ObjectTypeProperty', 'ObjectTypeSpreadProperty',\n  ]).has(node.type);\n}","tryCatchPattern":null,"preventionTips":["removeNode is for members/params/elements - not statements or expressions.","Delete statements with replaceStatementWithMany(stmt, []).","Mirror the whitelist from RemoveNode.js in a canRemoveNode guard."],"tags":["flow","flow-transform","codemod","remove-node","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"}