{"record":{"id":"fed679af756547e1","repo":"facebook/flow","slug":"flow-js-wasm-is-still-loading-await-flow-ready-fi","errorCode":null,"errorMessage":"flow.js wasm is still loading; await flow.ready first.","messagePattern":"flow\\.js wasm is still loading; await flow\\.ready first\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/flow_dot_js_wasm.js","lineNumber":212,"sourceCode":"        Module.onRuntimeInitialized = function () {\n          if (typeof onRuntimeInitialized === 'function') {\n            onRuntimeInitialized();\n          }\n          finish();\n        };\n      }\n    });\n  }\n  return flowDotJsReady;\n}\n\nfunction initWasm() {\n  if (flowDotJsWasmModule != null) {\n    return;\n  }\n  loadWasm();\n  if (flowDotJsWasmModule == null) {\n    throw new Error('flow.js wasm is still loading; await flow.ready first.');\n  }\n}\n\nfunction callRust(method, params) {\n  initWasm();\n  const request = encodeUtf8(JSON.stringify({method, params}));\n  const requestPtr = flowDotJsAlloc(request.length);\n  updateFlowDotJsMemoryViews();\n  let responsePtr = 0;\n  try {\n    flowDotJsWasmModule.HEAPU8.set(request, requestPtr);\n    responsePtr = flowDotJsCall(requestPtr, request.length);\n    updateFlowDotJsMemoryViews();\n    const response = JSON.parse(decodeHeapString(responsePtr));\n    if (!response.ok) {\n      throw new Error(response.error);\n    }\n    return response.value;","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/src/flow_dot_js_wasm.js#L194-L230","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)"],"exampleFix":"// before\nconst flow = require('flow.js');\nconst errors = flow.checkContent(a, b, 'foo.js', 'const x: number = \"s\";'); // throws: wasm is still loading\n\n// after\nconst flow = require('flow.js');\n(async () => {\n  await flow.ready;\n  const errors = flow.checkContent(a, b, 'foo.js', 'const x: number = \"s\";');\n})();","handlingStrategy":"validation","validationCode":"// run before any flow.js API call\nawait flow.ready; // resolves once installWasmModule has installed the exports","typeGuard":"// after installWasmModule runs it sets flowVersion from a live callRust(),\n// so a string flowVersion means the wasm module is installed.\nfunction isFlowJsReady(flow) {\n  return typeof flow.flowVersion === 'string';\n}","tryCatchPattern":"try {\n  flow.checkContent(a, b, file, code);\n} catch (e) {\n  if (e instanceof Error && /still loading/.test(e.message)) {\n    await flow.ready;\n    return flow.checkContent(a, b, file, code); // retry exactly once\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["wasm","async","initialization","race-condition","flow-js"],"backgroundTag":"wasm-module-not-loaded","analyzedSha":"f88ac94bcf6992f5d5a158854d94613ebb92c6e6","analyzedAt":"2026-08-20T10:41:37.992Z","contentChangedAt":"2026-08-20T10:41:37.992Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}