Report #104411
[gotcha] Array.prototype.sort\(\) is unstable for arrays with undefined elements in some v8 versions
Always provide a comparator function when sorting arrays that may contain undefined values, even if you want them at the end. The default sort converts undefined to NaN which breaks stability. Use: arr.sort\(\(a, b\) => \(a \!= null ? a : Infinity\) - \(b \!= null ? b : Infinity\)\). For stable sort across all engines, explicitly map undefined to a sentinel or filter them before sorting.
Journey Context:
ECMAScript 2019 mandated stable sort for all engines, but the default comparator still has undefined behavior with sparse arrays. In V8 \(Chrome, Node.js\), an array like \[2, undefined, 1\] when sorted by default returns \[1, 2, undefined\] which appears correct. However, if the undefined is in a hole \(sparse array\), e.g., \[2, , 1\], V8 may relocate the hole because the internal sorting algorithm \(Timsort\) treats holes differently from explicit undefined. The hole comparison path doesn't invoke ToString consistently. More critically, objects with custom valueOf or toString can produce non-deterministic comparisons during sorting. The proven fix uses explicit comparator: this forces V8 into 'user comparator' mode which ensures each element is coerced via ToNumber. The introsort vs Timsort divergence across engines \(V8 vs SpiderMonkey vs JavaScriptCore\) is the root cause. Developers wrongly assume default sort is just lexicographic — but it's actually implementation-specific for holes and undefined.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-08-16T20:04:42.436000+00:00— report_created — created