Repository navigation
perf_hooks.performance.timerify() with histogram: RangeError [ERR_OUT_OF_RANGE] on arm64 #41641
Description
Version
v14, v16, v17, v18, v26
Platform
macOS v12.4 (21F79).
Darwin 21.5.0 Darwin Kernel Version 21.5.0: Tue Apr 26 21:08:37 PDT 2022; root:xnu-8020.121.3~4/RELEASE_ARM64_T6000 arm64
Subsystem
perf_hooks
What steps will reproduce the bug?
Run this snippet:
import {createHistogram, performance} from 'node:perf_hooks';
const fn = () => {};
const timerified = performance.timerify(fn, {histogram: createHistogram()});
for (let i = 0; i < 100_000; i++) {
try {
timerified();
} catch (error) {
console.error('Crashed on iteration', i);
throw error;
}
}How often does it reproduce? Is there a required condition?
100% consistent reproduction, requires arm64, maybe requires macOS.
What is the expected behavior?
Calling the timerified function returned from perf_hooks.performance.timerify() should successfully record to the histogram.
What do you see instead?
node:internal/errors:466
ErrorCaptureStackTrace(err);
^
RangeError [ERR_OUT_OF_RANGE]: The value of "val" is out of range. It must be a safe integer greater than 0. Received 0
at new NodeError (node:internal/errors:377:5)
at RecordableHistogram.record (node:internal/histogram:290:13)
at processComplete (node:internal/perf/timerify:40:15)
at timerified fn (node:internal/perf/timerify:88:5)
at file:///Users/jonah/programming/benchmark/index.mjs:9:3
at ModuleJob.run (node:internal/modules/esm/module_job:198:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:409:24)
at async loadESM (node:internal/process/esm_loader:85:5)
at async handleMainPromise (node:internal/modules/run_main:61:12) {
code: 'ERR_OUT_OF_RANGE'
}
Node.js v18.1.0
Additional information
Originally reported here: sindresorhus/yoctocolors#9 (comment)
The bug appears to be from the implementation of perf_hooks.performance.timerify() with a histogram, when calling the returned timerified function. The error comes from the input validation of RecordableHistogram#record(), attempting to record a value x < 1 will throw. For whatever reason timerify() seems to be recording an execution duration of 0 and trying to record that. See the error stacktrace for more info.
Activity
benjamingr commentedon Jan 22, 2022
cc @jasnell
jonahsnider commentedon May 28, 2022
I recently upgraded to an arm64 laptop and was able to update the description of this issue with more specific system details. I also fixed a bug in the provided snippet which caused the reported bug to never trigger.
Additionally, I was able to reproduce this bug on Node.js v18.1.0.
everett1992 commentedon Oct 5, 2023
We're still seeing this with node 18.18
https://github.com/nodejs/node/blob/v18.x/lib/internal/perf/timerify.js#L38-L40
is there any guarantee that two calls to performance.now() will return a different value?
github-actions commentedon Jun 25, 2026
This issue has been marked as stale due to 210 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.
jonahsnider commentedon Jun 25, 2026
Still occurring for me on Node v26:
github-actions commentedon Sep 25, 2026
This issue has been marked as stale due to 90 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.
jonahsnider commentedon Sep 25, 2026
Still able to reproduce on v26.10.0:
perf_hooks: allow RecordableHistogram to record 0
lib: fix stream loading bug in node:bench
lib: fix stream loading bug in node:bench
perf_hooks: allow RecordableHistogram to record 0
lib: fix stream loading bug in node:bench
lib: fix stream loading bug in node:bench
perf_hooks: allow RecordableHistogram to record 0
perf_hooks: allow RecordableHistogram to record 0