facebook/flow · error · InvalidRemovalError

Tried to remove from parent of type . However can only be…

Error message

Tried to remove ${node.type} from parent of type ${node.parent.type}.
However ${node.type} can only be safely removed from parent of type ${expectedParents.join(' | ')}.

What it means

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.

Solutions

  1. Check `node.parent.type` before calling removeNode on an Identifier.
  2. Remove the enclosing node instead: VariableDeclarator removal for `const x = ...`, Property removal for object members.
  3. To rename, use replaceNode on the Identifier rather than remove+insert.
  4. For destructured params, remove the whole AssignmentPattern or its outer ArrayPattern/ObjectPattern.

Example fix

// before
mutate.removeNode(varDeclarator.id); // Identifier under VariableDeclarator - throws

// after
mutate.removeNode(varDeclarator); // removes the whole `x = init`
Defensive patterns

Strategy: type-guard

Validate before calling

const IDENTIFIER_REMOVAL_PARENTS = new Set([
  'ArrowFunctionExpression', 'FunctionDeclaration', 'FunctionExpression',
  'ArrayExpression', 'ArrayPattern',
]);

if (node.type === 'Identifier' && IDENTIFIER_REMOVAL_PARENTS.has(node.parent.type)) {
  mutate.removeNode(node);
} else if (node.type === 'Identifier' && node.parent.type === 'VariableDeclarator') {
  mutate.removeNode(node.parent); // remove the declarator instead
}

Type guard

function canRemoveIdentifier(node): boolean {
  return node.type === 'Identifier' && [
    'ArrowFunctionExpression', 'FunctionDeclaration', 'FunctionExpression',
    'ArrayExpression', 'ArrayPattern',
  ].includes(node.parent.type);
}

Try / catch

try {
  mutate.removeNode(node);
} catch (e) {
  if (e.name === 'InvalidRemovalError') { /* remove an enclosing node instead */ }
  else throw e;
}

Prevention

When it happens

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

Common situations: 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).

Related errors


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

Appendix: source

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

      case 'Property':
        assertParent(VALID_PROPERTY_PARENTS);
        return 'properties';

      // Identifier can be the child of a number of usecases
      case 'Identifier':
        switch (node.parent.type) {
          case 'ArrowFunctionExpression':
          case 'FunctionDeclaration':
          case 'FunctionExpression':
            return 'params';

          case 'ArrayExpression':
          case 'ArrayPattern':
            return 'elements';

          default:
            throw new InvalidRemovalError(
              getErrorMessage([
                'ArrowFunctionExpression',
                'FunctionDeclaration',
                'FunctionExpression',
                'ArrayExpression',
                'ArrayPattern',
              ]),
            );
        }

      // RestElement can be the child of a number of usecases
      case 'RestElement':
        switch (node.parent.type) {
          case 'ArrowFunctionExpression':
          case 'FunctionDeclaration':
          case 'FunctionExpression':
          case 'ComponentDeclaration':
            return 'params';

View on GitHub (pinned to f88ac94bcf)