Skip to content

@sentry/wasm: wasm://wasm/ frames miss debug_meta on non-streaming instantiate(buffer) #23781

Description

@d2anamaria

Description

Problem

fetch → arrayBuffer() → WebAssembly.instantiate(buffer) can produce frames like:
wasm://wasm/0bee4c4e:wasm-function[1]:0x8c (no file URL).

Module is registered, but patchFrames fails: streaming regex matches first, getImage('wasm://wasm/…') misses, debug_meta.images never attached.

Works / breaks

  • ✅ instantiateStreaming
  • ✅ instantiate(buffer) when stack has http://…/file.wasm:wasm-function[…] (Emscripten, dev Rust)
  • ❌ instantiate(buffer) + wasm://wasm/… (minimal wasm, e2e simple.wasm)
  • ❌ 2+ registered wasm modules (wasm://wasm/<id> not mappable)
  • ❌ module not registered (no build_id / untagged buffer)

Proposed fix

  1. Handle wasm://wasm/… before streaming regex
  2. Map to sole registered module when count === 1
  3. postprocessEvent hook
  4. Browser e2e: suites/wasm/nonStreaming/

Limitation

Single registered wasm module only until multi-module mapping exists.

Activity

  1. linear-code commented on Aug 31, 2026

    @linear-code
  2. arpitbharadwaj1 commented on Sep 1, 2026

    @arpitbharadwaj1

    Traced this through packages/wasm/src/ — can confirm the root cause precisely, one level more specific than the "streaming regex matches first" framing above.

    The actual gap: patchWebAssembly() (patchWebAssembly.ts) only wraps WebAssembly.instantiateStreaming and WebAssembly.compileStreaming. It does not wrap WebAssembly.instantiate at all. So for the fetch → arrayBuffer() → WebAssembly.instantiate(buffer) path, registerModule() is never called — the module is never added to registry.ts's IMAGES array in the first place, under any key. patchFrames's PARSER_REGEX actually parses wasm://wasm/0bee4c4e:wasm-function[1]:0x8c fine (match[1] comes out as wasm://wasm/0bee4c4e) — getImage('wasm://wasm/0bee4c4e') just correctly returns -1 because nothing was ever registered.

    Why there's no obvious fix by just "patching instantiate too": unlike the streaming path, which has response.url to register the image under, WebAssembly.instantiate(bufferSource, importObject) has no URL at all — there's no fetch response in the picture. That's exactly why V8 falls back to the synthetic wasm://wasm/<hash> frame identifier: there's no real source URL to report. So even after patching instantiate to call WebAssembly.compile(buffer) (to get a Module and read its build_id/external_debug_info custom sections) and calling registerModule(module, <?>), there's no way to register under a key that will deterministically match V8's synthetic per-module hash — which is exactly why the proposed fix's step 2 (map to the sole registered module when count === 1) is a heuristic, not a lookup, and why the limitation is scoped to single-module registration until there's a real cross-reference between a compiled Module and its later-generated stack-frame identifier.

    On implementation, two overload wrinkles worth flagging before writing this:

    1. WebAssembly.instantiate has two overloads — (bufferSource, importObject?) (compiles and instantiates, needs a WebAssembly.compile() call inserted to get a Module for reading custom sections) vs. (moduleObject, importObject?) (module already compiled — should probably also register, no extra compile needed). The patch needs to branch on arg instanceof WebAssembly.Module.
    2. Registering under a placeholder/sentinel key (rather than a real URL) needs getImage's lookup path (via patchFrames) to specifically recognize the wasm://wasm/ frame shape as "look for the sole non-URL-registered image" rather than doing its normal exact-string match — that logic lives in index.ts, not registry.ts, so the fix spans both files plus the new patchWebAssembly.ts interception.

    I don't have a way to compile a real .wasm binary with build_id/external_debug_info custom sections and run it through an actual browser (the existing test suite's suites/wasm/* tests need a real compiled binary, simple.wasm, and Playwright) to verify an implementation end-to-end in this environment, which is why I'm sharing this as source-level confirmation rather than a PR. Happy to implement it against the plan above (and the suites/wasm/nonStreaming/ test suite you mentioned) if that's a useful next step, or if you already have a WIP branch for this given how precisely-scoped your proposed fix already reads.

  3. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Sep 1, 2026
  4. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 3on Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions