facebook/flow · error · InvalidRemovalError

Cannot perform a remove mutation on node of type

Error message

Cannot perform a remove mutation on node of type ${node.type}

What it means

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.

Solutions

  1. To delete a statement, use `mutate.replaceStatementWithMany(stmt, [])` instead of removeNode.
  2. 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).
  3. Check RemoveNode.js's switch statement for the current whitelist before choosing the node to remove.

Example fix

// before
mutate.removeNode(exprStatement); // 'Cannot perform a remove mutation on node of type ExpressionStatement'

// after
mutate.replaceStatementWithMany(exprStatement, []);
Defensive patterns

Strategy: type-guard

Validate before calling

const REMOVABLE_TYPES = new Set([
  'PropertyDefinition', 'MethodDefinition',
  'EnumBooleanMember', 'EnumDefaultedMember', 'EnumNumberMember', 'EnumStringMember',
  'ComponentParameter', 'ComponentTypeParameter',
  'AssignmentPattern', 'ArrayPattern', 'ObjectPattern', 'FunctionTypeParam',
  'JSXAttribute', 'ImportDeclaration',
  'ObjectTypeCallProperty', 'ObjectTypeIndexer', 'ObjectTypeInternalSlot',
  'ObjectTypeProperty', 'ObjectTypeSpreadProperty', 'Property',
  'Identifier', 'RestElement', 'SpreadElement',
]);

if (REMOVABLE_TYPES.has(node.type)) {
  mutate.removeNode(node);
} else {
  mutate.replaceStatementWithMany(node, []); // statements: replace with nothing
}

Type guard

function canRemoveNode(node): boolean {
  return new Set([
    'PropertyDefinition', 'MethodDefinition', 'Property', 'JSXAttribute',
    'ImportDeclaration', 'Identifier', 'RestElement', 'SpreadElement',
    'AssignmentPattern', 'ArrayPattern', 'ObjectPattern', 'FunctionTypeParam',
    'ComponentParameter', 'ComponentTypeParameter',
    'EnumBooleanMember', 'EnumDefaultedMember', 'EnumNumberMember', 'EnumStringMember',
    'ObjectTypeCallProperty', 'ObjectTypeIndexer', 'ObjectTypeInternalSlot',
    'ObjectTypeProperty', 'ObjectTypeSpreadProperty',
  ]).has(node.type);
}

Prevention

When it happens

Trigger: `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.

Common situations: Trying to delete a whole statement or expression directly; the most common codemod mistake when removing a call statement instead of the enclosing statement.

Related errors


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

Appendix: source

Thrown at packages/flow-transform/src/transform/mutations/RemoveNode.js:270

          case 'OptionalCallExpression':
          case 'CallExpression':
          case 'NewExpression':
            return 'arguments';

          default:
            throw new InvalidRemovalError(
              getErrorMessage([
                'ArrayExpression',
                'ObjectExpression',
                'CallExpression',
                'OptionalCallExpression',
                'NewExpression',
              ]),
            );
        }

      default:
        throw new InvalidRemovalError(
          `Cannot perform a remove mutation on node of type ${node.type}`,
        );
    }
  })();

  const targetIndex = (() => {
    // $FlowExpectedError[prop-missing]
    const arr = node.parent[key];
    const idx = arr.indexOf(node);
    // $FlowFixMe[invalid-compare]
    if (idx === -1) {
      throw new InvalidRemovalError(
        `Could not find target in array of \`${node.parent.type}.${key}\`.`,
      );
    }
    return idx;
  })();

View on GitHub (pinned to f88ac94bcf)