facebook/flow · error · Error

createTranslationContext: Module scope not found

Error message

createTranslationContext: Module scope not found

What it means

createTranslationContext (TranslationUtils.js) builds the translator's reference/variable maps from scopeManager.globalScope.childScopes[0] and requires that scope to be of type 'module'. If the first child scope is missing or is a function scope, the code was analyzed as a script rather than a module, and the context cannot be built.

Source

Thrown at packages/flow-api-translator/src/utils/TranslationUtils.js:39

export type TranslationContext = {
  scopeManager: ScopeManager,
  referenceMap: Map<Identifier | JSXIdentifier, Variable>,
  variableMap: Map<Dep, Variable>,
  recoverFromErrors: boolean,
  mungeUnderscores: boolean,
  code: string,
};

export function createTranslationContext(
  code: string,
  scopeManager: ScopeManager,
  {recoverFromErrors, mungeUnderscores = true}: TranslationOptions,
): TranslationContext {
  const referenceMap = new Map<Identifier | JSXIdentifier, Variable>();
  const variableMap = new Map<Dep, Variable>();
  const moduleScope = scopeManager.globalScope.childScopes[0];
  if (moduleScope == null || moduleScope.type !== 'module') {
    throw new Error('createTranslationContext: Module scope not found');
  }
  for (const variable of moduleScope.variables) {
    for (const reference of variable.references) {
      referenceMap.set(reference.identifier, variable);
      variableMap.set(variable.name, variable);
    }
  }
  return {
    scopeManager,
    referenceMap,
    variableMap,
    recoverFromErrors,
    mungeUnderscores,
    code,
  };
}

View on GitHub (pinned to f88ac94bcf)

Solutions

  1. Parse and analyze the code with sourceType: 'module' so eslint-scope creates a module scope under the global scope.
  2. Use the public translateFlowToFlowDef / translateFlowToJS APIs instead of internals; they enforce module parsing.
  3. If a file has no module syntax, add an `export {}` or an @flow pragma plus module parse to force module mode.
  4. Validate childScopes[0].type === 'module' before building the context and emit a clear 'parse as module' error.

Example fix

// before
const scopeManager = analyze(parse(code, {sourceType: 'script'}));
const ctx = createTranslationContext(code, scopeManager, {recoverFromErrors: false});

// after
const scopeManager = analyze(parse(code, {sourceType: 'module', flow: 'all'}));
const ctx = createTranslationContext(code, scopeManager, {recoverFromErrors: false});
Defensive patterns

Strategy: validation

Validate before calling

// Confirm module scope exists before building a translation context
function hasModuleScope(scopeManager) {
  const first = scopeManager.globalScope.childScopes[0];
  return first != null && first.type === 'module';
}
if (!hasModuleScope(scopeManager)) {
  throw new Error('parse/analyze the code with sourceType: "module" before translation');
}

Type guard

function isModuleScope(scope) {
  return scope != null && scope.type === 'module';
}

Prevention

When it happens

Trigger: Invoking translator internals (flowToFlowDef/flowToFlowDef-family) with a ScopeManager produced from script-mode source: parsing with sourceType 'script', or 'unambiguous' resolution landing on script for a file without import/export and without module indicators. The public APIs parse with sourceType module, so this mainly hits direct internal callers.

Common situations: Feeding CommonJS-style files (no imports/exports) through a pipeline that parses with unambiguous/script; reusing a scopeManager from a different parser configuration; writing custom tooling on top of flow-api-translator internals.

Related errors


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