facebook/flow · error · InvalidStatementError
Attempted to insert a statement into
Error message
Attempted to insert a statement into `${parentWithType.type}.${key}`. What it means
InvalidStatementError thrown by getStatementParent's `assertValidStatementLocation` helper. Statement mutations (insertStatement*/remove of statements) resolve where the anchor statement lives; for parent types like IfStatement, ForStatement, LabeledStatement, etc. the code first asserts the anchor is NOT sitting in a non-statement slot such as `IfStatement.test`, `ForStatement.init`, `LabeledStatement.label`, or `ForInStatement.left/right`. If you passed one of those non-statement nodes as the anchor, this error names the offending `ParentType.key`.
Solutions
- Only use statement mutations on actual Statement/ModuleDeclaration nodes.
- From an expression node, walk up parents until you reach a node whose type ends in 'Statement' or is a Declaration, then anchor on that.
- For expressions, use replaceNode instead of statement insertions.
Example fix
// before
mutate.insertStatementBefore(callNode.parent.test, stmt); // anchor in IfStatement.test - throws
// after - walk up to the real statement
let anchor = callNode;
while (anchor.parent && !/Statement|Declaration$/.test(anchor.parent.type) === false) { /* ... */ }
mutate.insertStatementBefore(enclosingStatement, stmt); Defensive patterns
Strategy: type-guard
Validate before calling
const NON_STATEMENT_SLOTS = new Map([
['IfStatement', ['test']], ['ForStatement', ['init', 'test', 'update']],
['LabeledStatement', ['label']], ['WithStatement', ['object']],
['WhileStatement', ['test']], ['DoWhileStatement', ['test']],
['ForInStatement', ['left', 'right']], ['ForOfStatement', ['left', 'right']],
]);
function occupiesStatementSlot(node): boolean {
const bad = NON_STATEMENT_SLOTS.get(node.parent.type) ?? [];
const inBadSlot = bad.some(k => node.parent[k] === node);
return !inBadSlot && /Statement|Declaration$/.test(node.type);
}
if (occupiesStatementSlot(anchor)) mutate.insertStatementBefore(anchor, stmt); Type guard
function isStatementNode(node): boolean {
return typeof node.type === 'string' &&
(/Statement$/.test(node.type) || /Declaration$/.test(node.type));
} Prevention
- Pass only Statement/ModuleDeclaration nodes to statement mutations.
- From an expression, walk up to the enclosing statement first.
- Use replaceNode for expression-level changes.
When it happens
Trigger: Calling `mutate.insertStatementBefore(ifStatement.test, ...)` or otherwise using an expression node (the anchor's parent holds it in a test/init/label/left/right/object slot) where a Statement is required.
Common situations: Visitors that match expression nodes (CallExpression, Identifier) and then call a statement mutation relative to `node` or `node.parent` without checking that the node actually occupies a statement slot.
Related errors
- Could not find target in array of
- Expected to find a valid statement parent, but found a…
- Expected to find the target
- Cannot perform a remove mutation on node of type
- Could not find target in array of
AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20).
Data as JSON: /api/errors/7b0b048b4f23119c.
Report an issue: GitHub.
Appendix: source
Thrown at packages/flow-transform/src/transform/mutations/utils/getStatementParent.js:51
},
>;
export function getStatementParent(
target: ModuleDeclaration | Statement,
): StatementParent {
function assertValidStatementLocation<
T extends Readonly<interface {type: string}>,
>(parentWithType: T, ...invalidKeys: ReadonlyArray<keyof T>): void {
for (const key of invalidKeys) {
// $FlowExpectedError[prop-missing]
const value = parentWithType[key];
if (
// $FlowFixMe[invalid-compare]
value === target ||
(Array.isArray(value) && value.includes(target))
) {
throw new InvalidStatementError(
`Attempted to insert a statement into \`${parentWithType.type}.${key}\`.`,
);
}
}
}
function getAssertedIndex(key: string, arr: ReadonlyArray<unknown>): number {
const idx = arr.indexOf(target);
if (idx === -1) {
throw new InvalidStatementError(
`Could not find target in array of \`${parent.type}.${key}\`.`,
);
}
return idx;
}
const parent = target.parent;
const result: StatementParent = (() => {
switch (parent.type) {View on GitHub (pinned to f88ac94bcf)