workerd icon indicating copy to clipboard operation
workerd copied to clipboard

🐛 BUG: Uncaught error when initializing two top level WASM modules

Open pi0 opened this issue 1 year ago • 5 comments

Which Cloudflare product(s) does this pertain to?

Miniflare

What version(s) of the tool(s) are you using?

3.20231218.0

What version of Node are you using?

v20.10.0

What operating system are you using?

Mac

Describe the Bug

When using dynamic imports to load two wasm modules in parallel using top-level await, any second await attempt failed with an uncaught error.

Minimal Reproduction: https://github.com/pi0/miniflare-reproduction

mode-a.mjs and mode-b.mjs:

const mod = (await import("./sum.wasm")).default;
const instance = await WebAssembly.instantiate(mod);

export const sum = instance.exports.sum;

worker.mjs:

let [a, b] = ["-", "-"];

// Only works if one await happens!
a = await import("./mod-a.mjs").then((r) => r.sum(1, 2));
b = await import("./mod-b.mjs").then((r) => r.sum(3, 4));

export default {
  async fetch(request, env, ctx) {
    // This works (also in parallel)
    // a = await import("./mod-a.mjs").then((r) => r.sum(1, 2));
    // b = await import("./mod-b.mjs").then((r) => r.sum(3, 4));

    return new Response(JSON.stringify([a, b], null, 2), {
      headers: { "content-type": "application/json" },
    });
  },
};

Note: Importing alone works, but any attempt to access or call exports fails with error:

Stack trace: (attached)

(minfilare config uses modules: true + moduleRules for CompiledWasm)


Context: Discovered in tests while working on https://github.com/unjs/unwasm/pull/11/ (unwasm will be used as the default WASM handler for Nuxt and Nitro projects and also for CF deployments 🔥 ) the

Please provide a link to a minimal reproduction

https://github.com/pi0/miniflare-reproduction

Please provide any relevant error logs

workerd/jsg/modules.c++:336: error: Async module was not immediately resolved.
service core:user:: Uncaught ReferenceError: Cannot access 'sum' before initialization
  at src/worker.mjs:5:47
/Users/pooya/tmp/miniflare-reproduction/node_modules/miniflare/dist/src/index.js:8890
      throw new MiniflareCoreError(
            ^

MiniflareCoreError [ERR_RUNTIME_FAILURE]: The Workers runtime failed to start. There is likely additional logging output above.
    at #assembleAndUpdateConfig (/Users/pooya/tmp/miniflare-reproduction/node_modules/miniflare/dist/src/index.js:8890:13)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Mutex.runWith (/Users/pooya/tmp/miniflare-reproduction/node_modules/miniflare/dist/src/index.js:3861:16)
    at async #waitForReady (/Users/pooya/tmp/miniflare-reproduction/node_modules/miniflare/dist/src/index.js:8940:5)
    at async Miniflare.dispatchFetch (/Users/pooya/tmp/miniflare-reproduction/node_modules/miniflare/dist/src/index.js:9004:5)

pi0 avatar Jan 05 '24 12:01 pi0

Fantastic minimal reproduction! Thank you @pi0 I suspect this is an issue with workerd itself rather than Miniflare...

petebacondarwin avatar Jan 05 '24 14:01 petebacondarwin

Ideally we need a reproduction that only uses workerd, then I can transfer this over to https://github.com/cloudflare/workerd

petebacondarwin avatar Jan 05 '24 14:01 petebacondarwin

I just tried deploying the worker and it actually seems to be working fine in workerd 😕 : https://wasm-bug-worker.dario-piotrowicz.workers.dev/

Could this be related to how Miniflare imports such modules rather than there being something wrong in workerd itself?

dario-piotrowicz avatar Jan 05 '24 14:01 dario-piotrowicz

I managed to reproduce this just with workerd: https://github.com/petebacondarwin/toplevel-async-wasm-workerd-repro

So I propose we transfer this issue there...

Interestingly @pi0 - the issue can be avoided if you do not use the async WebAssembly.instantiate() call but instead use the sync new WebAssembly.Instance() constructor.

petebacondarwin avatar Jan 11 '24 11:01 petebacondarwin

We've experienced the same error: Async module was not immediately resolved running workerd locally. It seems that top-level await is simply not supported.

isker avatar Aug 02 '24 21:08 isker