I've been working on a wasm instrumentation pipeline that rewrites core modules and composes them into components with ComponentEncoder. Part of my workflow involves diffing the transpiled JS output between the original and instrumented components to make sure instrumentation is purely additive.
I noticed the postReturn and callback variable assignments sometimes pick different representative export names between runs. This happens when multiple cabi_post_* or [callback] exports alias the same core function, which wit-bindgen produces pretty commonly for shared deallocation logic. The wasm itself is correct and the runtime behaviour is fine, it's just the JS picking a different name each time.
I tracked it down to Translation::exports() returning a HashMap. When core_export_var_name iterates it with find_map to resolve a function index back to a name, HashMap's iteration order varies between runs (Rust randomizes the hash seed per process), so it picks a different representative each time. It looks like this changed from IndexMap to HashMap in 39e6972d during the recent wasmtime deps update when exports moved to Atom-keyed maps. That commit is only about a week old so figured it's worth catching early.
I've put together a fix in #1373 that switches the return type back to IndexMap so export iteration preserves wasm binary order. The change is small. indexmap = "2" added to Cargo.toml and the return type of Translation::exports() switched from HashMap to IndexMap. indexmap is already in Cargo.lock (resolves to 2.13.0) as a transitive dependency so no new crates to pull in. I went with "2" since we don't need any specific 2.x features, just IndexMap itself. I verified it across 5 transpile runs on the same component and the output is now identical every time.
Would love to hear how the project thinks about transpile determinism generally, for our pipeline it's pretty important for diffing and caching. Either way the fix felt straightforward enough to send along.
Last updated: Apr 13 2026 at 00:25 UTC