Skip to content

[Bug]: Non-deterministic output: deduplicated assets take their filename from emission order #9940

Description

@mitio

Reproduction link or steps

Turns out rolldown's build is non-deterministic when you have identical content under different names in your bundle tree. The minimal reproduction is just 2 identical files, each imported by its own module and then one final entry file:

src/assets/alpha.png   # identical content with beta.png
src/assets/beta.png    # identical content with alpha.png
src/mod_a.js           # import u from './assets/alpha.png'; export default u
src/mod_b.js           # import u from './assets/beta.png';  export default u
src/entry.js           # import './mod_a.js'; import './mod_b.js'; console.log(...)

What is expected?

The build process should produce the same output every time when ran with the same input content.

When deduplicating assets, the file name chosen to be used should be deterministically-determined.

What is actually happening?

Here's how I believe it happens:

When two emitted assets have identical content but different names (e.g. the same logo under two filenames, imported as asset modules), rolldown deduplicates them by content hash and the surviving asset's output filename is taken from whichever copy emits first. Assets emit concurrently from parallel module processing and which one is emitted first is thus non-deterministic, especially on systems with multiple processors. The one name of the deduplicated asset chosen by this process then lands in [name] of assetFileNames, so it changes the bytes — and therefore the [hash] — of every chunk that references that duplicate asset. That's how byte-identical input produces different asset and chunk hashes per build.

System Info

rolldown 1.1.2

This happens on macOS (Apple Silicon) and Ubuntu Linux (arm64, multi-core) as well. Don't think this would be relevant but let me know if it is and I'll add more info.

The system info below is from StackBlitz:

  System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 22.22.3 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 10.8.2 - /usr/local/bin/npm
    pnpm: 8.15.6 - /usr/local/bin/pnpm
  npmPackages:
    rolldown: 1.1.2 => 1.1.2

Any additional comments?

We were hit quite bad by this at Dext (other factors were at play as well, of course, but this non-determinism was one of the required conditions...) It would be great if we manage to resolve it.

Full disclosure: the reproduction was created with the help of Claude Code. I did try to simplify it as much as possible and massaged its output. Looks absolutely legit to me but I might have missed something.

Metadata

Metadata

Assignees

Type

Fields

Priority

None yet

Effort

None yet

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions