facebook/flow · error · Error

updatePendingStatements: Variable parent of

Error message

updatePendingStatements: Variable parent of "${dep}" not found

What it means

Companion to error 3 in the same loop: the dependency's Variable was found in context.variableMap, but one of its scope definitions has def.node == null, so translation cannot locate the AST statement that defines it and throws. It indicates the variable exists in the module scope without an attached defining node (implicit/ambient definitions rather than a concrete declaration).

Solutions

  1. Replace reliance on implicit globals with explicit declarations (`declare var require: any;` style) or imports in the input file.
  2. Run with recoverFromErrors: true to let the translator emit error comments and continue.
  3. Isolate the dependency named in the message and inspect how it is defined; rewrite it as a normal top-level declaration.
  4. Report the repro upstream if the definition is a plain top-level statement, since def.node should then be set.

Example fix

// before
exports.make = () => require('./util'); // implicit module/require

// after
import util from './util';
export const make = () => util;
Defensive patterns

Strategy: try-catch

Validate before calling

// Detect dependencies whose defs lack a defining node before translating
function depsWithMissingDefNode(context, deps) {
  return deps.filter((d) => {
    const v = context.variableMap.get(d);
    return v == null || v.defs.some((def) => def.node == null);
  });
}

Type guard

function hasConcreteDefs(variable) {
  return variable != null && variable.defs.length > 0 && variable.defs.every((d) => d.node != null);
}

Try / catch

try {
  const {code: out} = await translateFlowToFlowDef({code, recoverFromErrors: true});
} catch (e) {
  const m = /Variable parent of "(.+)" not found/.exec(e.message);
  if (m) {
    report(`"${m[1]}" resolves to an implicit/ambient definition — rewrite it as an explicit top-level declaration`);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: translateFlowToFlowDef input whose dependency resolves to a module-scope Variable whose defs array contains a Definition with a null node (implicit globals, injected builtins like require/module, or scope-analysis artifacts), so getTopLevelStatement has no statement to enqueue.

Common situations: Converting files that use CommonJS injected names (require, module, exports) or ambient implicit globals as dependencies of exported declarations; scope-manager versions whose Definition.node is optional for some def types.

Related errors


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

Appendix: source

Thrown at packages/flow-api-translator/src/flowToFlowDef.js:425

  const seenDeps = new Set<Dep>();
  const processedStatements = new Set<ProgramStatement>();
  const pendingStatements = new Set<ProgramStatement>();
  function updatePendingStatements(deps: TranslatedDeps): void {
    for (const dep of deps) {
      if (seenDeps.has(dep)) {
        continue;
      }
      seenDeps.add(dep);
      const variable = context.variableMap.get(dep);
      if (variable == null) {
        throw new Error(
          `updatePendingStatements: Variable for dependency "${dep}" not found`,
        );
      }
      for (const def of variable.defs) {
        const stmt = def.node;
        if (stmt == null) {
          throw new Error(
            `updatePendingStatements: Variable parent of "${dep}" not found`,
          );
        }
        const topLevelStmt = getTopLevelStatement(stmt, context);
        if (processedStatements.has(topLevelStmt)) {
          continue;
        }
        pendingStatements.add(topLevelStmt);
      }
    }
  }
  function updateProcessedStatement(stmt: ProgramStatement): void {
    processedStatements.add(stmt);
    pendingStatements.delete(stmt);
  }

  // Process all export statements
  for (const stmt of ast.body) {

View on GitHub (pinned to 21c11b2ead)