facebook/flow · error · Error
flowImportTo: Unexpected transform result.
Error message
flowImportTo: Unexpected transform result.
What it means
flowImportTo runs SimpleTransform.transform over the passed AST and requires the result to be a non-null Program node; anything else is an invalid transform result and throws. The built-in visitor only rewrites module specifiers of import/export declarations, so in practice this throw means the root you passed was not a Program or a custom transform removed the root.
Source
Thrown at packages/flow-api-translator/src/flowImportTo.js:70
case 'DeclareExportAllDeclaration':
case 'ExportAllDeclaration':
case 'DeclareExportDeclaration':
case 'ExportNamedDeclaration': {
if (node.source != null) {
return SimpleTransform.nodeWith(node, {
source: mapSource(node.source),
});
}
return node;
}
default: {
return node;
}
}
},
});
if (result == null || result.type !== 'Program') {
throw new Error('flowImportTo: Unexpected transform result.');
}
return result;
}
View on GitHub (pinned to f88ac94bcf)
Solutions
- Pass the Program node itself: const {type: 'Program'} AST from flow-parser parse(), not a child or wrapper node.
- Prefer the public translateFlowImportsTo API, which parses and drives flowImportTo correctly.
- If you forked the visitor, ensure every branch (especially for Program) returns a single ESNode, never null or an array.
- Add an assertion ast.type === 'Program' before calling to fail with a clearer message.
Example fix
// before
const result = flowImportTo(ast.body[0], code, scopeManager, opts);
// after
const ast = parse(code, {sourceType: 'module', flow: 'all'});
const result = flowImportTo(ast, code, scopeManager, opts); Defensive patterns
Strategy: validation
Validate before calling
function isProgram(node) {
return node != null && typeof node === 'object' && node.type === 'Program';
}
// before calling:
if (!isProgram(ast)) throw new TypeError('flowImportTo requires the Program node'); Type guard
function isProgram(node) {
return node != null && typeof node === 'object' && node.type === 'Program';
} Try / catch
try {
renamed = flowImportTo(ast, code, scopeManager, {sourceMapper});
} catch (e) {
if (e.message.startsWith('flowImportTo:')) {
// root was not a Program or a custom transform removed it
throw new Error(`flowImportTo got ${ast?.type ?? 'null'}; pass the parsed Program node`);
}
throw e;
} Prevention
- Always pass the Program node returned by parse(), never ast.body or a wrapper node.
- Prefer the public translateFlowImportsTo API over calling flowImportTo directly.
- In forked visitors, guarantee every branch returns a single ESNode for the root.
When it happens
Trigger: Calling flowImportTo directly (or translateFlowImportsTo) with a non-Program root, e.g. a File wrapper, a Statement, or an AST produced by a prior transform whose root was replaced/removed. Any visitor returning null or an array for the Program node also triggers it.
Common situations: Pipelines that chain transforms and accidentally hand flowImportTo a subtree instead of the whole Program; custom forks of the visitor that drop nodes at the root; passing an AST from a different parser whose root type is not 'Program'.
Related errors
- Unexpected function parameter ${param.type}
- SimpleTransform: invalid array result for root node
- SimpleTransform.transformProgram: Expected program node.
- unable to resolve scope
- updatePendingStatements: Variable for dependency "${dep}" no
AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20).
Data as JSON: /api/errors/53943a0ceef631c2.
Report an issue: GitHub.