Skip to content

Turbopack: stale browserslist-rs data causes all SWC compat transforms to be enabled, panicking on ** operator #92091

@mhdsdt

Description

@mhdsdt

Link to the code that reproduces this issue

https://github.com/mhdsdt/turbopack-bigint-exponentiation-repro

To Reproduce

  1. Clone: git clone https://github.com/mhdsdt/turbopack-bigint-exponentiation-repro
  2. npm install --force
  3. npm run dev (runs next dev --turbopack)
  4. Open http://localhost:3000 -- 500 error with Rust panic

The reproduction is a single page with an async function using the ** operator and a standard browserslist (>0.2%, not dead, not op_mini all) in package.json. No external dependencies beyond Next.js and React.

npm run dev:webpack works fine.

Current vs. Expected behavior

Current: Turbopack panics:

thread 'tokio-runtime-worker' panicked at
  swc_ecma_compat_es2015-42.0.0/src/generator.rs:507:21:
  not yet implemented: right-associative binary expression

Expected: The page should compile successfully. The ** operator is standard ES2016, async is standard ES2017, and every browser in the >0.2%, not dead list supports both natively.

Root cause (traced through source code):

There is a caniuse-lite data version mismatch between the JS and Rust sides of the Turbopack pipeline:

  1. Next.js resolves the browserslist on the JS side using an up-to-date caniuse-lite (knows Chrome 146, Firefox 149, etc.), then sends the resolved browser strings to Turbopack (hot-reloader-turbopack.ts:280)
  2. Turbopack re-resolves them using browserslist-rs v0.19.0 (published July 2025, only knows up to ~Chrome 141) with ignore_unknown_versions: true, so unknown versions are silently dropped, returning an empty distribution list
  3. Versions::parse_versions([]) returns all-None fields
  4. is_any_target() returns true (all None = "unknown target")
  5. When is_any_target is true, every SWC compat transform is enabled, including async-to-generator and the ES2015 generator transform
  6. async-to-generator converts the async function into a generator
  7. The generator transform encounters ** and panics at todo!("right-associative binary expression")

Why this only affects Turbopack (not webpack on canary):

SWC PR #11457 (merged Jan 2026) added an unknown_version flag to preset_env: when a browserslist query returns empty results, it assumes a modern browser and skips all transforms. Webpack benefits from this because SWC's targets_to_versions correctly sets unknown_version: true on empty results.

Turbopack bypasses this fix. It pre-resolves the browserslist in Rust (environment.rs:96-97), then passes already-parsed versions via Targets::Versions(versions) (transform/mod.rs:206), which always sets unknown_version: false in targets_to_versions. The unknown_version guard never fires.

Chrome version boundary test:

Browserslist Result Why
No browserslist OK Uses hardcoded defaults (chrome 111, edge 111, firefox 111, safari 16.4)
chrome 141 OK Known to browserslist-rs 0.19.0
chrome 142 Panic Unknown to browserslist-rs, silently dropped, is_any_target = true
firefox 130 OK Known
firefox 148 Panic Unknown
>0.2%, not dead Panic Resolves to Chrome 142+, Firefox 147+, etc.
>1% OK Happens to resolve to only known versions

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.3.0
  Available memory (MB): 24576
  Available CPU cores: 10
Binaries:
  Node: 20.20.0
  npm: 10.8.2
  Yarn: 1.22.22
  pnpm: 10.24.0
Relevant Packages:
  next: 16.2.1-canary.13
  eslint-config-next: N/A
  react: 19.2.4
  react-dom: 19.2.4
  typescript: 5.9.3
Next.js Config:
  output: N/A

Which area(s) are affected?

Turbopack, SWC

Which stage(s) are affected?

next dev (local), next build (local)

Additional context

This will affect more and more projects over time as browsers release new versions that browserslist-rs 0.19.0 doesn't know about. Any project with a standard browserslist (>0.2% is the Create React App default) will eventually hit this.

In real-world projects, the panic typically manifests through node_modules packages that contain async functions with the ** operator, since Turbopack transpiles node_modules (unlike webpack). Known affected packages include permissionless, @noble/curves, and @walletconnect/utils.

Possible fixes:

  1. Update browserslist-rs in Turbopack to match the JS-side caniuse-lite data
  2. Detect when parse_versions returns all-None and set unknown_version: true in Turbopack's preset-env config, so the existing SWC fix (allow use global typescript, without install on local project #11457) applies
  3. Pass the browserslist query string to SWC instead of pre-resolving it in Rust, so Turbopack uses the same code path as webpack

Key source locations:

Related: pimlicolabs/permissionless.js#499 (same error, reported on the wrong repo)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions