facebook/flow · error · InvalidStatementError

Expected to find a valid statement parent, but found a…

Error message

Expected to find a valid statement parent, but found a parent of type "${parent.type}".

What it means

InvalidStatementError thrown at the end of getStatementParent's switch: statement mutations only support anchors whose parent is one of IfStatement, LabeledStatement, WithStatement, DoWhileStatement, WhileStatement, ForStatement, ForInStatement, ForOfStatement, SwitchCase, BlockStatement, or Program. Any other parent type (e.g. ExportDefaultDeclaration, ClassBody, or an expression parent) falls through to this throw.

Solutions

  1. Ensure the anchor is a direct Statement/ModuleDeclaration child of one of the supported parent types.
  2. For expression-level changes, use replaceNode/replaceNodeWithContext instead of statement mutations.
  3. If a legitimate statement location is unsupported, upstream a case to getStatementParent.

Example fix

// before
mutate.insertStatementBefore(expressionNode, stmt); // parent not a statement container - throws

// after
mutate.insertStatementBefore(enclosingStatement, stmt);
Defensive patterns

Strategy: type-guard

Validate before calling

const STATEMENT_PARENTS = new Set([
  'IfStatement', 'LabeledStatement', 'WithStatement', 'DoWhileStatement',
  'WhileStatement', 'ForStatement', 'ForInStatement', 'ForOfStatement',
  'SwitchCase', 'BlockStatement', 'Program',
]);

if (STATEMENT_PARENTS.has(anchor.parent.type)) {
  mutate.insertStatementBefore(anchor, stmt);
}

Type guard

function hasSupportedStatementParent(anchor): boolean {
  return [
    'IfStatement', 'LabeledStatement', 'WithStatement', 'DoWhileStatement',
    'WhileStatement', 'ForStatement', 'ForInStatement', 'ForOfStatement',
    'SwitchCase', 'BlockStatement', 'Program',
  ].includes(anchor.parent.type);
}

Prevention

When it happens

Trigger: Calling insertStatement*/statement removal with an anchor whose parent type is not in the supported list - commonly an expression node whose parent is a CallExpression/VariableDeclarator, or a declaration nested somewhere the switch does not model.

Common situations: Passing a non-Statement node as the anchor (same root cause as the `test`/`init` assertion but hitting the fall-through instead); new or unusual AST shapes not covered by the supported-parent switch.

Related errors


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

Appendix: source

Thrown at packages/flow-transform/src/transform/mutations/utils/getStatementParent.js:130

          type: 'array',
          parent,
          key: 'consequent',
          targetIndex: getAssertedIndex('consequent', parent.consequent),
        };
      }

      case 'BlockStatement':
      case 'Program': {
        return {
          type: 'array',
          parent,
          key: 'body',
          targetIndex: getAssertedIndex('body', parent.body),
        };
      }
    }

    throw new InvalidStatementError(
      `Expected to find a valid statement parent, but found a parent of type "${parent.type}".`,
    );
  })();

  if (
    // array insertions are already validated by the getAssertedIndex function
    result.targetIndex == null &&
    // $FlowExpectedError[prop-missing]
    // $FlowFixMe[invalid-compare]
    result.parent[result.key] !== target
  ) {
    throw new InvalidStatementError(
      `Expected to find the target "${target.type}" on the "${result.parent.type}.${result.key}", but found a different node. ` +
        'This likely means that you attempted to mutate around the target after it was deleted/replaced.',
    );
  }

  return result;

View on GitHub (pinned to f88ac94bcf)