{"record":{"id":"a1be01f370a63cda","repo":"facebook/flow","slug":"tried-to-remove-node-type-from-parent-of-type-a1be01","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 ArrowFunctionExpression | FunctionDeclaration | FunctionExpression | ComponentDeclaration | ArrayPattern | ObjectPattern | CallExpression | OptionalCallExpression | NewExpression.","messagePattern":"Tried to remove (.+?) from parent of type (.+?)\\.\nHowever (.+?) can only be safely removed from parent of type ArrowFunctionExpression \\| FunctionDeclaration \\| FunctionExpression \\| ComponentDeclaration \\| ArrayPattern \\| ObjectPattern \\| CallExpression \\| OptionalCallExpression \\| NewExpression\\.","errorType":"exception","errorClass":"InvalidRemovalError","httpStatus":null,"severity":"error","filePath":"packages/flow-transform/src/transform/mutations/RemoveNode.js","lineNumber":226,"sourceCode":"          case 'FunctionExpression':\n          case 'ComponentDeclaration':\n            return 'params';\n\n          case 'ArrayPattern':\n            return 'elements';\n\n          case 'ObjectPattern':\n            return 'properties';\n\n          // $FlowFixMe[incompatible-type]\n          // $FlowFixMe[invalid-compare]\n          case 'OptionalCallExpression':\n          case 'CallExpression':\n          case 'NewExpression':\n            return 'arguments';\n\n          default:\n            throw new InvalidRemovalError(\n              getErrorMessage([\n                'ArrowFunctionExpression',\n                'FunctionDeclaration',\n                'FunctionExpression',\n                'ComponentDeclaration',\n                'ArrayPattern',\n                'ObjectPattern',\n                'CallExpression',\n                'OptionalCallExpression',\n                'NewExpression',\n              ]),\n            );\n        }\n\n      // SpreadElement can be the child of a number of usecases\n      case 'SpreadElement':\n        switch (node.parent.type) {\n          case 'ArrayExpression':","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/facebook/flow/blob/d1341dac899a79c027762f6b423d896045287620/packages/flow-transform/src/transform/mutations/RemoveNode.js#L208-L244","documentation":"The RestElement case of removeNodeMutation allows removal from params (function-likes plus ComponentDeclaration), elements (ArrayPattern), properties (ObjectPattern), and arguments (Call, New, and OptionalCallExpression). Every other parent type falls to the default and throws InvalidRemovalError with the full allowlist in the message. The allowlist exists because each allowed slot is an array the mutation engine can splice safely; other rest positions (e.g. under an AssignmentPattern) would produce unprintable code.","triggerScenarios":"removeNodeMutation(restElement) where the RestElement's parent is an AssignmentPattern, a VariableDeclarator's pattern, or any node not in the allowlist: for example removing the rest from destructuring assignment where the supported parent chain does not apply.","commonSituations":"Codemods normalizing function signatures that also walk destructuring sites; refactoring tools that hoist rest params and hit the rest inside assignment destructuring.","solutions":["Only request removal when the RestElement's parent type is in the allowlist (check node.parent.type first)","For unsupported positions, replace the enclosing pattern or declarator with a rebuilt node using replaceNodeMutation instead","When the error message prints an unexpected parent type, re-check the traversal: you are likely matching rests in assignments, not params"],"exampleFix":"// before\nmutations.push(removeNode(node)); // node = RestElement under AssignmentPattern\n\n// after\nconst OK = ['ArrowFunctionExpression','FunctionDeclaration','FunctionExpression','ComponentDeclaration','ArrayPattern','ObjectPattern','CallExpression','OptionalCallExpression','NewExpression'];\nif (OK.includes(node.parent.type)) {\n  mutations.push(removeNode(node));\n} else {\n  mutations.push(replaceWith(node.parent, rebuildWithoutRest(node.parent)));\n}","handlingStrategy":"type-guard","validationCode":"const REST_REMOVE_PARENTS = new Set(['ArrowFunctionExpression', 'FunctionDeclaration', 'FunctionExpression', 'ComponentDeclaration', 'ArrayPattern', 'ObjectPattern', 'CallExpression', 'OptionalCallExpression', 'NewExpression']);\nfunction canRemoveRestElement(node) {\n  return node.type === 'RestElement' && REST_REMOVE_PARENTS.has(node.parent.type);\n}","typeGuard":"const isRemovableRestElement = (node) =>\n  node.type === 'RestElement' && ['ArrowFunctionExpression', 'FunctionDeclaration', 'FunctionExpression', 'ComponentDeclaration', 'ArrayPattern', 'ObjectPattern', 'CallExpression', 'OptionalCallExpression', 'NewExpression'].includes(node.parent && node.parent.type);","tryCatchPattern":null,"preventionTips":["Check node.parent.type against the allowlist before removeNodeMutation on a RestElement","For unsupported positions, rebuild and replace the enclosing pattern instead of removing","Remember rests inside assignment destructuring usually sit under unsupported parents: replace, do not remove"],"tags":["flow-transform","removal","rest-element","parent-type"],"backgroundTag":"unsupported-ast-node-removal","analyzedSha":"d1341dac899a79c027762f6b423d896045287620","analyzedAt":"2026-08-17T00:07:02.212Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}