nextjs - 💡(How to fix) Fix Turbopack: WASM fetch URLs break on Vercel due to double-encoded ?dpl= deployment suffix [1 comments, 2 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#91778Fetched 2026-04-08 01:12:05
View on GitHub
Comments
1
Participants
2
Timeline
5
Reactions
0
Author
Timeline (top)
labeled ×2closed ×1commented ×1locked ×1

Root Cause

In the Turbopack runtime (turbopack-*.js), the q() function constructs asset URLs:

let r = (self.TURBOPACK_ASSET_SUFFIX ?? document?.currentScript?.getAttribute?.("src")?.replace(/^(.*(?=\?)|^.*$)/, "")) || "";

function q(e) {
  return `${t}${e.split("/").map(e => encodeURIComponent(e)).join("/")}${r}`;
}

The suffix r captures ?dpl=dpl_xxx from the script tag's src attribute. When loadWebAssembly calls fetch(q(r)), it passes the WASM chunk name through encodeURIComponent, which correctly encodes the path segments. But the WASM chunk name itself doesn't contain the suffix — it's appended by ${r} at the end.

The problem is that for JS/CSS chunks loaded via <script> and <link> tags, the browser handles the URL correctly. But for WASM loaded via fetch(q(path)), the encodeURIComponent on path segments combined with the suffix produces a malformed URL.

Specifically, the WASM path goes through encodeURIComponent which is fine, but the constructed URL ends up as:

/_next/static/chunks/05667dwwroz~t.wasm?dpl=dpl_xxx

which then gets the suffix appended again, or the path itself somehow includes the encoded suffix.

Fix Action

Workaround

Use next build --webpack instead of Turbopack for production builds and configure webpack with asyncWebAssembly: true.

Code Example

let r = (self.TURBOPACK_ASSET_SUFFIX ?? document?.currentScript?.getAttribute?.("src")?.replace(/^(.*(?=\?)|^.*$)/, "")) || "";

function q(e) {
  return `${t}${e.split("/").map(e => encodeURIComponent(e)).join("/")}${r}`;
}

---

/_next/static/chunks/05667dwwroz~t.wasm?dpl=dpl_xxx

---

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin 25.2.0

Binaries:
  Node: 24.12.0
  npm: 11.4.0
  Yarn: N/A
  pnpm: 10.10.0

Relevant Packages:
  next: 16.2.1
  react: 19.2.1
  react-dom: 19.2.1
  typescript: 5.9.3
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

Any Next.js 16.2 app deployed to Vercel that imports a WASM module (e.g. via @sovereign-sdk/universal-wallet-wasm which does import * as wasm from "./wallet_wasm_bg.wasm").

To Reproduce

  1. Create a Next.js 16.2 app that depends on a package using ESM WASM imports
  2. Configure turbopack.rules with "*.wasm": { type: "wasm" }
  3. Deploy to Vercel
  4. Open browser console

Current vs. Expected behavior

Expected: WASM file loads successfully from /_next/static/chunks/05667dwwroz~t.wasm?dpl=dpl_xxx

Actual: Browser requests /_next/static/chunks/05667dwwroz~t.wasm%3Fdpl%3Ddpl_xxx?dpl=dpl_xxx which returns 404.

The ?dpl=dpl_xxx query string gets URL-encoded as part of the filename path (%3F and %3D), then appended again as a proper query parameter.

Root cause

In the Turbopack runtime (turbopack-*.js), the q() function constructs asset URLs:

let r = (self.TURBOPACK_ASSET_SUFFIX ?? document?.currentScript?.getAttribute?.("src")?.replace(/^(.*(?=\?)|^.*$)/, "")) || "";

function q(e) {
  return `${t}${e.split("/").map(e => encodeURIComponent(e)).join("/")}${r}`;
}

The suffix r captures ?dpl=dpl_xxx from the script tag's src attribute. When loadWebAssembly calls fetch(q(r)), it passes the WASM chunk name through encodeURIComponent, which correctly encodes the path segments. But the WASM chunk name itself doesn't contain the suffix — it's appended by ${r} at the end.

The problem is that for JS/CSS chunks loaded via <script> and <link> tags, the browser handles the URL correctly. But for WASM loaded via fetch(q(path)), the encodeURIComponent on path segments combined with the suffix produces a malformed URL.

Specifically, the WASM path goes through encodeURIComponent which is fine, but the constructed URL ends up as:

/_next/static/chunks/05667dwwroz~t.wasm?dpl=dpl_xxx

which then gets the suffix appended again, or the path itself somehow includes the encoded suffix.

Workaround

Use next build --webpack instead of Turbopack for production builds and configure webpack with asyncWebAssembly: true.

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin 25.2.0

Binaries:
  Node: 24.12.0
  npm: 11.4.0
  Yarn: N/A
  pnpm: 10.10.0

Relevant Packages:
  next: 16.2.1
  react: 19.2.1
  react-dom: 19.2.1
  typescript: 5.9.3

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

Turbopack

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

next build (default)

Additional context

  • The WASM file is correctly emitted to .next/static/chunks/ during build
  • The file serves correctly when accessed directly (without the double-encoded suffix)
  • This only manifests on Vercel deployments that use the ?dpl= deployment suffix
  • pnpm dev (Turbopack dev server) works fine since there's no deployment suffix

extent analysis

Fix Plan

To fix the issue with Turbopack and WASM imports on Vercel, you can use the following approaches:

  • Use Webpack instead of Turbopack: Configure next build to use Webpack by running next build --webpack and set asyncWebAssembly: true in your Webpack configuration.
  • Modify Turbopack runtime: Update the q() function in the Turbopack runtime to correctly handle the URL suffix.

Here's an example of how you can modify the q() function:

function q(e) {
  const url = `${t}${e.split("/").map(e => encodeURIComponent(e)).join("/")}`;
  if (r) {
    return `${url}${r.includes('?') ? '&' : '?'}${r.replace(/^(\?|&)/, '')}`;
  }
  return url;
}

Alternatively, you can also try to update the next.config.js file to include the following configuration:

module.exports = {
  //... other configurations ...
  experimental: {
    turbopack: {
      asyncWebAssembly: true,
    },
  },
}

Verification

To verify that the fix worked, you can check the browser console for any errors related to the WASM file loading. You can also inspect the network requests to ensure that the WASM file is being loaded correctly.

Extra Tips

  • Make sure to test your application thoroughly after applying the fix to ensure that it works as expected.
  • If you're using a CDN or a caching layer, you may need to invalidate the cache to ensure that the updated files are served correctly.
  • Keep an eye on the Turbopack and Next.js issues trackers for any updates or fixes related to this issue.

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