facebook/flow · error · Error
flow.js wasm is still loading; await flow.ready first.
Error message
flow.js wasm is still loading; await flow.ready first.
What it means
Every flow.js API call goes through callRust -> initWasm(). The WASM module is instantiated asynchronously: loadWasm() starts the load and stores the promise in flowDotJsReady, which is exported as flow.ready (src/flow_dot_js_wasm.js:345). initWasm() throws this error when loadWasm() has been kicked off but flowDotJsWasmModule is still null, i.e. the Emscripten module has not finished instantiating yet.
Solutions
- Await flow.ready once before the first API call (same pattern as src/__tests__/flow_dot_js_smoke_test.js: await flow.ready)
- Gate every flow entry point behind a shared async init wrapper so callers cannot bypass the await
- If using the modular factory form, make sure flow_dot_js_wasm() is defined and resolves before calls (the promise path installs exports in installWasmModule)
- In browsers, verify the .wasm binary is fetched successfully (a failed fetch keeps the module null and this error rethrows on later calls)
Example fix
// before
const flow = require('flow.js');
const errors = flow.checkContent(a, b, 'foo.js', 'const x: number = "s";'); // throws: wasm is still loading
// after
const flow = require('flow.js');
(async () => {
await flow.ready;
const errors = flow.checkContent(a, b, 'foo.js', 'const x: number = "s";');
})(); Defensive patterns
Strategy: validation
Validate before calling
// run before any flow.js API call await flow.ready; // resolves once installWasmModule has installed the exports
Type guard
// after installWasmModule runs it sets flowVersion from a live callRust(),
// so a string flowVersion means the wasm module is installed.
function isFlowJsReady(flow) {
return typeof flow.flowVersion === 'string';
} Try / catch
try {
flow.checkContent(a, b, file, code);
} catch (e) {
if (e instanceof Error && /still loading/.test(e.message)) {
await flow.ready;
return flow.checkContent(a, b, file, code); // retry exactly once
}
throw e;
} Prevention
- Await flow.ready in a single init step before exposing any flow calls to the rest of the app
- Never call flow APIs at module top-level; always inside the async path that awaited ready
- In test setups, await flow.ready in beforeAll exactly as the smoke test does
When it happens
Trigger: Calling any exported flow.js method (checkContent, parse, completions, flowVersion after install, etc.) synchronously right after require/import, before the ready promise resolves. Calling flow from module top-level code or a non-async callback that races the WASM instantiation.
Common situations: Editor/IDE integrations and LSP servers that query flow during startup; test harnesses that invoke flow without awaiting ready; slower environments (big WASM binary, cold cache, CI) where instantiation takes longer than the caller assumed; refactors that moved the first flow call outside the async init path.
Related errors
- Daemon child: failed to set TCP_NODELAY on parent out-socket
- Daemon child: failed to set TCP_NODELAY on parent in-socket
- Expected File, got
- Expected Program, got
- failed to spawn init thread
AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20).
Data as JSON: /api/errors/fed679af756547e1.
Report an issue: GitHub.
Appendix: source
Thrown at src/flow_dot_js_wasm.js:212
Module.onRuntimeInitialized = function () {
if (typeof onRuntimeInitialized === 'function') {
onRuntimeInitialized();
}
finish();
};
}
});
}
return flowDotJsReady;
}
function initWasm() {
if (flowDotJsWasmModule != null) {
return;
}
loadWasm();
if (flowDotJsWasmModule == null) {
throw new Error('flow.js wasm is still loading; await flow.ready first.');
}
}
function callRust(method, params) {
initWasm();
const request = encodeUtf8(JSON.stringify({method, params}));
const requestPtr = flowDotJsAlloc(request.length);
updateFlowDotJsMemoryViews();
let responsePtr = 0;
try {
flowDotJsWasmModule.HEAPU8.set(request, requestPtr);
responsePtr = flowDotJsCall(requestPtr, request.length);
updateFlowDotJsMemoryViews();
const response = JSON.parse(decodeHeapString(responsePtr));
if (!response.ok) {
throw new Error(response.error);
}
return response.value;View on GitHub (pinned to f88ac94bcf)