nextjs - ✅(Solved) Fix Web Worker fails to load WASM with Turbopack: "Failed to execute 'fetch' on 'WorkerGlobalScope'" (blob URL context) [1 pull requests, 4 comments, 5 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#84782Fetched 2026-04-08 02:18:24
View on GitHub
Comments
4
Participants
5
Timeline
17
Reactions
6
Timeline (top)
commented ×4cross-referenced ×3labeled ×3subscribed ×3

Error Message

  1. Observe error: When running my Next.js app with Turbopack (next dev --turbo), my web worker fails to load a WASM file. The error shown is:

Fix Action

Fixed

PR fix notes

PR #88602: Turbopack: Use a real file entrypoint for Workers (and SharedWorkers)

Description (problem / solution / changelog)

What

Closes https://github.com/vercel/next.js/issues/84782
Closes https://github.com/vercel/next.js/issues/74842
Closes https://github.com/vercel/next.js/issues/82520 Closes PACK-3723

Replace blob URLs for web workers with real entrypoint files, fixing relative URL resolution inside workers. Implements support for SharedWorkers since it's now a simple variation of the Worker case.

Note that all generated files (and shared-worker querystrings) are appropriately content-hashed and do not rely on deployment IDs and will work w/immutable resources.

Why

Workers created via new Worker(new URL('./worker.js', import.meta.url)) previously got blob URLs. This breaks relative URL resolution inside workers - WASM imports like new URL('./file.wasm', import.meta.url) fail because import.meta.url returns blob:http://... instead of a real path.

How

We emit a real worker entrypoint file instead of blob URLs. The entrypoint reads bootstrap config from URL hash params (#params=....), then loads the worker's chunks via importScripts.

The ChunkingContext trait gets a new worker_entrypoint() method returning a singleton bootstrap asset. Node.js bail!s for now but could implement its own in the future. The browser implementation (EcmascriptBrowserWorkerEntrypoint) compiles and minifies worker-entrypoint.ts, which parses #params={globals,chunks} from the URL at runtime.

WorkerLoaderChunkItem now emits __turbopack_worker_url__(entrypoint, chunks, shared) instead of the old blob URL shim. SharedWorker passes shared=true which adds a querystring - the browser handles worker identity via URL, so same URL means same instance.

Generated code changes (pseudocode):

__turbopack_export_value__(__turbopack_worker_blob_url__(["chunk1.js", "chunk2.js"]));

After:

__turbopack_export_value__(__turbopack_worker_url__("worker-entrypoint.js", ["chunk1.js", "chunk2.js"], false));

Notes

Webpack doesn't currently correctly support SharedWorkers. The e2e test behaves properly in turbopack after this change, but webpack spins up two separate workers where it should only be spinning up one.

I generated snapshot tests for workers in the first and last commits to help understand the generated code better.

Testing

  • Snapshot tests for Worker, SharedWorker, and minified output
  • E2E tests for WASM loading in workers (test/e2e/app-dir/worker/)

Changed files

  • test/e2e/app-dir/worker/app/add.wasm (added, +0/-0)
  • test/e2e/app-dir/worker/app/shared-worker.ts (added, +8/-0)
  • test/e2e/app-dir/worker/app/shared/page.js (added, +39/-0)
  • test/e2e/app-dir/worker/app/wasm-worker.ts (added, +22/-0)
  • test/e2e/app-dir/worker/app/wasm/page.js (added, +27/-0)
  • test/e2e/app-dir/worker/worker.test.ts (modified, +36/-1)
  • turbopack/crates/turbopack-browser/src/chunking_context.rs (modified, +13/-0)
  • turbopack/crates/turbopack-browser/src/ecmascript/mod.rs (modified, +2/-0)
  • turbopack/crates/turbopack-browser/src/ecmascript/worker.rs (added, +132/-0)
  • turbopack/crates/turbopack-core/src/chunk/chunking_context.rs (modified, +15/-1)
  • turbopack/crates/turbopack-core/src/output.rs (modified, +24/-7)
  • turbopack/crates/turbopack-core/src/resolve/mod.rs (modified, +1/-1)
  • turbopack/crates/turbopack-ecmascript-runtime/js/src/browser/runtime/base/runtime-base.ts (modified, +31/-17)
  • turbopack/crates/turbopack-ecmascript-runtime/js/src/browser/runtime/base/worker-entrypoint.ts (added, +81/-0)
  • turbopack/crates/turbopack-ecmascript-runtime/js/src/browser/runtime/dom/runtime-backend-dom.ts (modified, +1/-1)
  • turbopack/crates/turbopack-ecmascript-runtime/js/src/nodejs/runtime.ts (modified, +7/-3)
  • turbopack/crates/turbopack-ecmascript-runtime/js/src/shared/runtime-types.d.ts (modified, +6/-2)
  • turbopack/crates/turbopack-ecmascript-runtime/src/browser_runtime.rs (modified, +12/-0)
  • turbopack/crates/turbopack-ecmascript-runtime/src/lib.rs (modified, +1/-1)
  • turbopack/crates/turbopack-ecmascript/src/analyzer/mod.rs (modified, +5/-0)
  • turbopack/crates/turbopack-ecmascript/src/references/mod.rs (modified, +22/-5)
  • turbopack/crates/turbopack-ecmascript/src/references/worker.rs (modified, +10/-6)
  • turbopack/crates/turbopack-ecmascript/src/runtime_functions.rs (modified, +2/-2)
  • turbopack/crates/turbopack-ecmascript/src/worker_chunk/chunk_item.rs (modified, +37/-6)
  • turbopack/crates/turbopack-ecmascript/src/worker_chunk/module.rs (modified, +21/-6)
  • turbopack/crates/turbopack-tests/tests/snapshot.rs (modified, +11/-6)
  • turbopack/crates/turbopack-tests/tests/snapshot/debug-ids/browser/output/aaf3a_crates_turbopack-tests_tests_snapshot_debug-ids_browser_input_index_0151fefb.js.map (modified, +5/-5)
  • turbopack/crates/turbopack-tests/tests/snapshot/debug-ids/browser/output/ba425_crates_turbopack-tests_tests_snapshot_debug-ids_browser_input_index_0151fefb.js (modified, +26/-21)
  • turbopack/crates/turbopack-tests/tests/snapshot/debug-ids/node/output/[turbopack]_runtime.js (modified, +3/-3)
  • turbopack/crates/turbopack-tests/tests/snapshot/debug-ids/node/output/[turbopack]_runtime.js.map (modified, +1/-1)
  • turbopack/crates/turbopack-tests/tests/snapshot/imports/ignore-comments/output/6642e_crates_turbopack-tests_tests_snapshot_imports_ignore-comments_output_2867ca5f._.js (added, +62/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/imports/ignore-comments/output/aaf3a_crates_turbopack-tests_tests_snapshot_imports_ignore-comments_input_1f8151c3._.js (modified, +1/-4)
  • turbopack/crates/turbopack-tests/tests/snapshot/imports/ignore-comments/output/aaf3a_crates_turbopack-tests_tests_snapshot_imports_ignore-comments_input_1f8151c3._.js.map (modified, +1/-1)
  • turbopack/crates/turbopack-tests/tests/snapshot/imports/ignore-comments/output/aaf3a_crates_turbopack-tests_tests_snapshot_imports_ignore-comments_output_2867ca5f._.js.map (added, +1/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/runtime/default_build_runtime/output/[turbopack]_runtime.js (modified, +3/-3)
  • turbopack/crates/turbopack-tests/tests/snapshot/runtime/default_build_runtime/output/[turbopack]_runtime.js.map (modified, +1/-1)
  • turbopack/crates/turbopack-tests/tests/snapshot/runtime/default_dev_runtime/output/5c1d0_turbopack-tests_tests_snapshot_runtime_default_dev_runtime_input_index_c0f7e0b0.js (modified, +24/-19)
  • turbopack/crates/turbopack-tests/tests/snapshot/runtime/default_dev_runtime/output/780ce_turbopack-tests_tests_snapshot_runtime_default_dev_runtime_input_index_c0f7e0b0.js.map (modified, +4/-4)
  • turbopack/crates/turbopack-tests/tests/snapshot/swc_transforms/preset_env/output/5c1d0_turbopack-tests_tests_snapshot_swc_transforms_preset_env_input_index_5aaf1327.js (modified, +26/-19)
  • turbopack/crates/turbopack-tests/tests/snapshot/swc_transforms/preset_env/output/780ce_turbopack-tests_tests_snapshot_swc_transforms_preset_env_input_index_5aaf1327.js.map (modified, +3/-3)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/basic/input/index.js (added, +3/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/basic/input/worker.js (added, +2/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/basic/options.json (added, +6/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/basic/output/6642e_crates_turbopack-tests_tests_snapshot_workers_basic_output_2867ca5f._.js (added, +62/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/basic/output/aaf3a_crates_turbopack-tests_tests_snapshot_workers_basic_input_index_96b0ffc6.js.map (added, +10/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/basic/output/aaf3a_crates_turbopack-tests_tests_snapshot_workers_basic_input_worker_01a12aa6.js.map (added, +10/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/basic/output/aaf3a_crates_turbopack-tests_tests_snapshot_workers_basic_input_worker_841f9693.js (added, +9/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/basic/output/aaf3a_crates_turbopack-tests_tests_snapshot_workers_basic_input_worker_841f9693.js.map (added, +6/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/basic/output/ba425_crates_turbopack-tests_tests_snapshot_workers_basic_input_index_96b0ffc6.js (added, +1869/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/basic/output/ba425_crates_turbopack-tests_tests_snapshot_workers_basic_input_worker_01a12aa6.js (added, +1869/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/basic/output/turbopack_crates_turbopack-tests_tests_snapshot_workers_basic_input_73fc86c5._.js (added, +22/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/basic/output/turbopack_crates_turbopack-tests_tests_snapshot_workers_basic_input_73fc86c5._.js.map (added, +6/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/basic/output/turbopack_crates_turbopack-tests_tests_snapshot_workers_basic_output_2867ca5f._.js.map (added, +1/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/basic/static/worker.60655f93.js (added, +2/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/shared/input/index.js (added, +2/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/shared/input/worker.js (added, +1/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/shared/options.json (added, +6/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/shared/output/6642e_crates_turbopack-tests_tests_snapshot_workers_shared_output_2867ca5f._.js (added, +62/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/shared/output/aaf3a_crates_turbopack-tests_tests_snapshot_workers_shared_input_index_818b7886.js.map (added, +10/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/shared/output/aaf3a_crates_turbopack-tests_tests_snapshot_workers_shared_input_worker_87533493.js.map (added, +10/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/shared/output/aaf3a_crates_turbopack-tests_tests_snapshot_workers_shared_input_worker_e14430d8.js (added, +8/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/shared/output/aaf3a_crates_turbopack-tests_tests_snapshot_workers_shared_input_worker_e14430d8.js.map (added, +6/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/shared/output/ba425_crates_turbopack-tests_tests_snapshot_workers_shared_input_index_818b7886.js (added, +1869/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/shared/output/ba425_crates_turbopack-tests_tests_snapshot_workers_shared_input_worker_87533493.js (added, +1869/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/shared/output/turbopack_crates_turbopack-tests_tests_snapshot_workers_shared_input_3845375a._.js (added, +21/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/shared/output/turbopack_crates_turbopack-tests_tests_snapshot_workers_shared_input_3845375a._.js.map (added, +6/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/shared/output/turbopack_crates_turbopack-tests_tests_snapshot_workers_shared_output_2867ca5f._.js.map (added, +1/-0)
  • turbopack/crates/turbopack-tests/tests/snapshot/workers/shared/static/worker.35b5336b.js (added, +1/-0)

Code Example

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Home
  Available memory (MB): 32503
  Available CPU cores: 24
Binaries:
  Node: 22.20.0
  npm: 10.9.3
  Yarn: N/A
  pnpm: 9.0.0
Relevant Packages:
  next: 15.5.0 // There is a newer version (15.5.4) available, upgrade recommended!
  eslint-config-next: N/A
  react: 19.1.0
  react-dom: 19.1.0
  typescript: 5.9.2
Next.js Config:
  output: N/A
There is a newer version (15.5.4) available, upgrade recommended!
   Please try the latest canary version (`npm install next@canary`) to confirm the issue still exists before creating a new issue.
   Read more - https://nextjs.org/docs/messages/opening-an-issue
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://codesandbox.io/p/devbox/crazy-leaf-m4yxw4

To Reproduce

  1. Open preview in new window
  2. Open chrome devtools (console)
  3. Observe error:
<img width="1173" height="288" alt="Image" src="https://github.com/user-attachments/assets/5b64b185-74a0-491a-9e8f-60140fcc73ba" />

Current vs. Expected behavior

Current behavior: When running my Next.js app with Turbopack (next dev --turbo), my web worker fails to load a WASM file. The error shown is:

Uncaught (in promise) TypeError: Failed to execute 'fetch' on 'WorkerGlobalScope': Failed to parse URL from openscad.wasm

The worker’s self.location.href is a blob URL (e.g., blob:http://localhost:3000/...), and the WASM file cannot be found or loaded.

Expected behavior: The web worker should be able to load the WASM file successfully, just as it does when running with the default Next.js dev server (Webpack), where the worker’s location is a normal HTTP URL and asset loading works as expected.

Provide environment information

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Home
  Available memory (MB): 32503
  Available CPU cores: 24
Binaries:
  Node: 22.20.0
  npm: 10.9.3
  Yarn: N/A
  pnpm: 9.0.0
Relevant Packages:
  next: 15.5.0 // There is a newer version (15.5.4) available, upgrade recommended!
  eslint-config-next: N/A
  react: 19.1.0
  react-dom: 19.1.0
  typescript: 5.9.2
Next.js Config:
  output: N/A
 ⚠ There is a newer version (15.5.4) available, upgrade recommended!
   Please try the latest canary version (`npm install next@canary`) to confirm the issue still exists before creating a new issue.
   Read more - https://nextjs.org/docs/messages/opening-an-issue

Which area(s) are affected? (Select all that apply)

Not sure, Turbopack

Which stage(s) are affected? (Select all that apply)

next dev (local)

Additional context

  • The issue occurs locally during development with Next.js using Turbopack (next dev --turbo).
  • The issue occurs inside of openscad.js
    • The script tries to load openscad.wasm like so: new URL("openscad.wasm",import.meta.url).href
    • I have found out that the script is a blob with turbopack and regular .js file with default Next.js dev server
  • The problem does not occur when running with the default Next.js dev server (Webpack).
  • The project is part of a Turborepo monorepo setup.

extent analysis

TL;DR

Upgrading to the latest version of Next.js (15.5.4) may resolve the issue with loading WASM files in web workers when using Turbopack.

Guidance

  • Verify that the issue persists with the latest version of Next.js (15.5.4) by running npm install [email protected] and then next dev --turbo.
  • Check if the problem is specific to Turbopack by comparing the behavior with the default Next.js dev server (Webpack).
  • Investigate the difference in how the script is loaded (as a blob with Turbopack vs. a regular .js file with Webpack) and how it affects the loading of the WASM file.
  • Consider modifying the script to handle the blob URL correctly, such as by using the URL constructor with the import.meta.url as the base.

Example

No code snippet is provided as the issue is more related to the configuration and setup of the project rather than a specific code problem.

Notes

The issue seems to be related to the difference in how Turbopack and Webpack handle the loading of scripts and assets. Upgrading to the latest version of Next.js may resolve the issue, but further investigation may be needed to determine the root cause.

Recommendation

Apply workaround: Upgrade to the latest version of Next.js (15.5.4) to see if it resolves the issue, as the current version (15.5.0) may have a bug that is causing the problem.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

nextjs - ✅(Solved) Fix Web Worker fails to load WASM with Turbopack: "Failed to execute 'fetch' on 'WorkerGlobalScope'" (blob URL context) [1 pull requests, 4 comments, 5 participants]