nextjs - ✅(Solved) Fix Turbopack: dynamic cyclical import causes infinite loop [1 pull requests, 2 comments, 3 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#85119Fetched 2026-04-08 02:17:22
View on GitHub
Comments
2
Participants
3
Timeline
15
Reactions
4
Timeline (top)
referenced ×4labeled ×3subscribed ×3commented ×2

Root Cause

By selectively commenting out imports, I see that this roughly caused by the following import chain:

Fix Action

Fixed

PR fix notes

PR #4959: Replace wasm_thread with web-thread

Description (problem / solution / changelog)

Motivation

Our hacked-up version of wasm_thread isn't a great fit for our use cases.

Firstly, wasm_thread aims to mimic the API of std::thread. This was never sufficient for us as we need to send non-Send messages across threads actively using postMessage, which std::thread has no equivalent for. We patched wasm_thread but it was at odds with the point of the package.

Then, in order to use wasm_thread without threading a shim script URL through the code down into linera-base, we dynamically got the URL of the wasm-bindgen shim script using import.meta.url. This is poorly (and inconsistently) supported by bundlers, which want to know what the URL will be used for; but since the Worker construction in wasm_thread is done in Rust code they cannot analyze it. This resulted in our @linera/client library being rather fragile under different bundlers, with workarounds required to ensure they don't interfere with the paths of the various files.

Proposal

Introduce the web-thread library, a simplified equivalent to wasm_thread that has a Web-first API, including a trait for types that can be passed by postMessage (including transferable objects), and whose worker logic is primarily implemented in JavaScript, making it much more comprehensible to bundlers.

This allows us:

Test Plan

The web-thread library itself has been tested with Vite as well as WebPack (via Next.js with the --webpack flag), and includes example applications to that effect.

I have manually tested our two Web applications in this repository.

I defer to CI for full tests of the native pathways.

Release Plan

  • Nothing to do / These changes follow the usual release cycle.

Links

Turbopack

Turbopack is currently not supported due to an open issue when processing cyclic dependencies. See the following discussions for more information:

Changed files

  • Cargo.lock (modified, +73/-50)
  • Cargo.toml (modified, +4/-5)
  • examples/Cargo.lock (modified, +60/-38)
  • examples/counter/package.json (modified, +1/-1)
  • examples/native-fungible/index.html (modified, +1/-1)
  • examples/native-fungible/package.json (modified, +1/-1)
  • examples/pnpm-lock.yaml (modified, +23/-13)
  • examples/vite.config.ts (modified, +0/-10)
  • linera-base/Cargo.toml (modified, +0/-7)
  • linera-base/src/lib.rs (modified, +1/-3)
  • linera-base/src/task.rs (modified, +13/-202)
  • linera-client/src/chain_listener.rs (modified, +5/-5)
  • linera-client/src/unit_tests/chain_listener.rs (modified, +2/-2)
  • linera-core/Cargo.toml (modified, +2/-0)
  • linera-core/src/chain_worker/actor.rs (modified, +45/-36)
  • linera-core/src/client/chain_client/mod.rs (modified, +1/-3)
  • linera-core/src/worker.rs (modified, +4/-4)
  • linera-execution/Cargo.toml (modified, +2/-1)
  • linera-execution/build.rs (modified, +1/-1)
  • linera-execution/src/execution.rs (modified, +6/-12)
  • linera-execution/src/execution_state_actor.rs (modified, +6/-12)
  • linera-execution/src/lib.rs (modified, +31/-29)
  • linera-execution/src/wasm/mod.rs (modified, +17/-22)
  • linera-sdk/tests/fixtures/Cargo.lock (modified, +31/-9)
  • linera-storage/Cargo.toml (modified, +1/-0)
  • linera-storage/src/lib.rs (modified, +10/-13)
  • web/@linera/client/package.json (modified, +1/-0)
  • web/@linera/client/tsconfig.json (modified, +2/-1)
  • web/pnpm-lock.yaml (modified, +3/-0)

Code Example

git clone https://github.com/maxpatiiuk/turbopack-dynamic-import-freeze.git
   cd turbopack-dynamic-import-freeze

---

npm install

---

npx next dev --turbopack
   # or:
   # CAUTION: the tracing file grows quickly, without limits
   NEXT_TURBOPACK_TRACING=1 npx next dev --turbopack

---

(also reproducible in Stackblitz)

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:29 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6000
  Available memory (MB): 32768
  Available CPU cores: 10
Binaries:
  Node: 22.19.0
  npm: 10.9.3
  Yarn: 1.22.19
  pnpm: 8.9.0
Relevant Packages:
  next: 15.5.6 // Latest available version is detected (15.5.6).
  eslint-config-next: N/A
  react: 19.2.0
  react-dom: 19.2.0
  typescript: 5.9.3
Next.js Config:
  output: N/A

---

NEXT_TURBOPACK_TRACING=1 MallocNanoZone=0 NODE_ENV=development NEXT_RUNTIME=nodejs TURBOPACK=1 NEXT_PRIVATE_WORKER=1 NEXT_PRIVATE_TRACE_ID=cb4e155e9cf7b89b WATCHPACK_WATCHER_LIMIT=20 node --inspect-brk node_modules/next/dist/server/lib/start-server.js
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/maxpatiiuk/turbopack-dynamic-import-freeze

To Reproduce

  1. Clone the repository

    git clone https://github.com/maxpatiiuk/turbopack-dynamic-import-freeze.git
    cd turbopack-dynamic-import-freeze

    OR: use the Stackblitz reproduction (but hard to debug in such environment):

  2. Install dependencies

    npm install
  3. Run the development server

    npx next dev --turbopack
    # or:
    # CAUTION: the tracing file grows quickly, without limits
    NEXT_TURBOPACK_TRACING=1 npx next dev --turbopack

100% cpu usage

Current vs. Expected behavior

If a module dynamically imports another module, which in turn dynamically imports the first module, Turbopack gets into a loop (100% CPU usage, trace file grows indefinitely).

My best minimal reproduction is in app/page.tsx, where a single library entrypoint import causes the loop.

I also attached the trace-turbopack file: trace-turbopack.zip Note it grows indefinitely, so I killed the process shortly after starting it to make the file uploadable to GitHub.

Provide environment information

(also reproducible in Stackblitz)

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:29 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6000
  Available memory (MB): 32768
  Available CPU cores: 10
Binaries:
  Node: 22.19.0
  npm: 10.9.3
  Yarn: 1.22.19
  pnpm: 8.9.0
Relevant Packages:
  next: 15.5.6 // Latest available version is detected (15.5.6).
  eslint-config-next: N/A
  react: 19.2.0
  react-dom: 19.2.0
  typescript: 5.9.3
Next.js Config:
  output: N/A

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

Module Resolution

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

next dev (local)

Additional context

I tried starting the server inside a debugger. The best I can tell the .js side is idle while native code is stuck in a loop:

NEXT_TURBOPACK_TRACING=1 MallocNanoZone=0 NODE_ENV=development NEXT_RUNTIME=nodejs TURBOPACK=1 NEXT_PRIVATE_WORKER=1 NEXT_PRIVATE_TRACE_ID=cb4e155e9cf7b89b WATCHPACK_WATCHER_LIMIT=20 node --inspect-brk node_modules/next/dist/server/lib/start-server.js

By selectively commenting out imports, I see that this roughly caused by the following import chain:

  • app/page.tsx imports @arcgis/core/portal/Portal
  • Portal.js has import("../Basemap")
  • Basemap.js has import { getLayerJSON as _ } from './webdoc/support/writeUtils.js';
  • writeUtils.js has import { isFeatureCollectionLayer as i } from '../../layers/support/layerUtils.js';
  • layerUtils.js has import { isLayerFromCatalog as r } from '../catalog/catalogUtils.js';
  • catalogUtils.js has import n from '../Layer.js';
  • Layer.js has import { fromPortalItem as m } from './support/fromPortalItem.js'; and import('./support/arcgisLayers.js') - either causes the issue
  • fromPortalItem.js has import('../../portal/support/portalLayers.js')
  • portalLayers.js has import { findAssociatedFeatureService as a } from '../../layers/support/associatedFeatureServiceUtils.js';
  • associatedFeatureServiceUtils.js has import o from '../../portal/Portal.js';

However, reducing the chain to a smaller reproduction is tricky. I hope the provided trace file can help you debug the root cause.

extent analysis

TL;DR

The issue can be fixed by refactoring the import chain to avoid circular dependencies between modules.

Guidance

  1. Identify and refactor circular imports: Analyze the provided import chain and identify the modules that are causing the circular dependency. Refactor the code to avoid these circular imports.
  2. Use lazy loading or dynamic imports: Consider using lazy loading or dynamic imports to load modules only when needed, which can help avoid circular dependencies.
  3. Verify the fix: Run the development server with the refactored code and monitor the CPU usage to ensure the issue is resolved.
  4. Analyze the trace file: Use the provided trace file to gain insights into the import chain and identify potential areas for optimization.
  5. Test with a smaller reproduction: Try to create a smaller reproduction of the issue to isolate the root cause and test the fix.

Example

No code example is provided as the issue is related to a complex import chain and requires a deeper analysis of the codebase.

Notes

The provided trace file and import chain suggest a complex issue that requires careful analysis and refactoring. The fix may involve significant changes to the codebase, and it's essential to test the changes thoroughly to ensure the issue is fully resolved.

Recommendation

Apply a workaround by refactoring the import chain to avoid circular dependencies. This approach is recommended as it addresses the root cause of the issue and provides a long-term solution.

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