From 0afb013090a81f517e5470c05d7e150ccd000e01 Mon Sep 17 00:00:00 2001 From: Minho Yoo <13810291+irontaek@users.noreply.github.com> Date: Wed, 14 Oct 2026 00:08:10 +0900 Subject: [PATCH 1/2] benchmark: throw on invalid type in fs and webstorage The default branch of the type switch constructed an Error without throwing it, so an unknown type silently benchmarked an undefined path instead of failing. Assisted-by: a closed-source coding agent Signed-off-by: Minho Yoo <13810291+irontaek@users.noreply.github.com> --- benchmark/fs/bench-accessSync.js | 2 +- benchmark/fs/bench-chmodSync.js | 2 +- benchmark/fs/bench-chownSync.js | 2 +- benchmark/fs/bench-existsSync.js | 2 +- benchmark/fs/bench-fchmodSync.js | 2 +- benchmark/fs/bench-fsyncSync.js | 2 +- benchmark/fs/bench-linkSync.js | 2 +- benchmark/fs/bench-mkdirSync.js | 2 +- benchmark/fs/bench-mkdtempSync.js | 2 +- benchmark/fs/bench-openSync.js | 2 +- benchmark/fs/bench-opendirSync.js | 2 +- benchmark/fs/bench-readSync.js | 2 +- benchmark/fs/bench-readlinkSync.js | 2 +- benchmark/fs/bench-rmdirSync.js | 2 +- benchmark/fs/bench-symlinkSync.js | 2 +- benchmark/fs/bench-timesSync.js | 2 +- benchmark/fs/bench-unlinkSync.js | 2 +- benchmark/fs/bench_fdatasyncSync.js | 2 +- benchmark/webstorage/getItem.js | 2 +- benchmark/webstorage/removeItem.js | 2 +- benchmark/webstorage/setItem.js | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/benchmark/fs/bench-accessSync.js b/benchmark/fs/bench-accessSync.js index 0be0ca799d3a..b4bc2a06a442 100644 --- a/benchmark/fs/bench-accessSync.js +++ b/benchmark/fs/bench-accessSync.js @@ -48,7 +48,7 @@ function main({ n, type, method }) { path = tmpdir.resolve(`.non-existing-file-${process.pid}`); break; default: - new Error('Invalid type'); + throw new Error('Invalid type'); } if (method === 'access') { diff --git a/benchmark/fs/bench-chmodSync.js b/benchmark/fs/bench-chmodSync.js index 87b45c06b507..97903db7b931 100644 --- a/benchmark/fs/bench-chmodSync.js +++ b/benchmark/fs/bench-chmodSync.js @@ -36,6 +36,6 @@ function main({ n, type }) { bench.end(n); break; default: - new Error('Invalid type'); + throw new Error('Invalid type'); } } diff --git a/benchmark/fs/bench-chownSync.js b/benchmark/fs/bench-chownSync.js index 18e2bd35d526..bcd83a342644 100644 --- a/benchmark/fs/bench-chownSync.js +++ b/benchmark/fs/bench-chownSync.js @@ -49,6 +49,6 @@ function main({ n, type, method }) { break; } default: - new Error('Invalid type'); + throw new Error('Invalid type'); } } diff --git a/benchmark/fs/bench-existsSync.js b/benchmark/fs/bench-existsSync.js index f9da2765b130..2b04eeb5167d 100644 --- a/benchmark/fs/bench-existsSync.js +++ b/benchmark/fs/bench-existsSync.js @@ -27,7 +27,7 @@ function main({ n, type }) { path = tmpdir.resolve(`.non-existing-file-${process.pid}`); break; default: - new Error('Invalid type'); + throw new Error('Invalid type'); } bench.start(); diff --git a/benchmark/fs/bench-fchmodSync.js b/benchmark/fs/bench-fchmodSync.js index 4ada8a6f5d8b..7023d0d1ff94 100644 --- a/benchmark/fs/bench-fchmodSync.js +++ b/benchmark/fs/bench-fchmodSync.js @@ -28,7 +28,7 @@ function main({ n, type }) { files = new Array(n).fill(tmpdir.resolve(`.non-existing-file-${Date.now()}`)); break; default: - new Error('Invalid type'); + throw new Error('Invalid type'); } const fds = files.map((x) => { diff --git a/benchmark/fs/bench-fsyncSync.js b/benchmark/fs/bench-fsyncSync.js index fc7ef2926679..672d91e369e4 100644 --- a/benchmark/fs/bench-fsyncSync.js +++ b/benchmark/fs/bench-fsyncSync.js @@ -24,7 +24,7 @@ function main({ n, type }) { fd = 1 << 30; break; default: - new Error('Invalid type'); + throw new Error('Invalid type'); } bench.start(); diff --git a/benchmark/fs/bench-linkSync.js b/benchmark/fs/bench-linkSync.js index ead39c338fe6..cb004837d26c 100644 --- a/benchmark/fs/bench-linkSync.js +++ b/benchmark/fs/bench-linkSync.js @@ -45,6 +45,6 @@ function main({ n, type }) { break; } default: - new Error('Invalid type'); + throw new Error('Invalid type'); } } diff --git a/benchmark/fs/bench-mkdirSync.js b/benchmark/fs/bench-mkdirSync.js index 1db1c5878776..08698b427eef 100644 --- a/benchmark/fs/bench-mkdirSync.js +++ b/benchmark/fs/bench-mkdirSync.js @@ -29,7 +29,7 @@ function main({ n, type, recursive }) { files = new Array(n).fill(__dirname); break; default: - new Error('Invalid type'); + throw new Error('Invalid type'); } bench.start(); diff --git a/benchmark/fs/bench-mkdtempSync.js b/benchmark/fs/bench-mkdtempSync.js index afb342366bbf..1e287493b6fe 100644 --- a/benchmark/fs/bench-mkdtempSync.js +++ b/benchmark/fs/bench-mkdtempSync.js @@ -27,7 +27,7 @@ function main({ n, type }) { prefix = tmpdir.resolve('non-existent', 'foo', 'bar'); break; default: - new Error('Invalid type'); + throw new Error('Invalid type'); } bench.start(); diff --git a/benchmark/fs/bench-openSync.js b/benchmark/fs/bench-openSync.js index b17c0a1e67f8..26ea1300b9ba 100644 --- a/benchmark/fs/bench-openSync.js +++ b/benchmark/fs/bench-openSync.js @@ -33,7 +33,7 @@ function main({ n, type }) { path = tmpdir.resolve(`.non-existing-file-${process.pid}`); break; default: - new Error('Invalid type'); + throw new Error('Invalid type'); } runBench({ n, path }); diff --git a/benchmark/fs/bench-opendirSync.js b/benchmark/fs/bench-opendirSync.js index f24faa5d5e69..2ea68192b587 100644 --- a/benchmark/fs/bench-opendirSync.js +++ b/benchmark/fs/bench-opendirSync.js @@ -25,7 +25,7 @@ function main({ n, type }) { files = [tmpdir.resolve(`.non-existing-file-${Date.now()}`)]; break; default: - new Error('Invalid type'); + throw new Error('Invalid type'); } bench.start(); diff --git a/benchmark/fs/bench-readSync.js b/benchmark/fs/bench-readSync.js index a75d1750002f..fea37f4c43c9 100644 --- a/benchmark/fs/bench-readSync.js +++ b/benchmark/fs/bench-readSync.js @@ -38,7 +38,7 @@ function main({ n, type }) { fd = 1 << 30; break; default: - new Error('Invalid type'); + throw new Error('Invalid type'); } const buffer = Buffer.alloc(bufferSize); diff --git a/benchmark/fs/bench-readlinkSync.js b/benchmark/fs/bench-readlinkSync.js index 9b3bbceb42e9..57a5611b9f3e 100644 --- a/benchmark/fs/bench-readlinkSync.js +++ b/benchmark/fs/bench-readlinkSync.js @@ -49,6 +49,6 @@ function main({ n, type }) { break; } default: - new Error('Invalid type'); + throw new Error('Invalid type'); } } diff --git a/benchmark/fs/bench-rmdirSync.js b/benchmark/fs/bench-rmdirSync.js index 481034392743..71002d41c5a1 100644 --- a/benchmark/fs/bench-rmdirSync.js +++ b/benchmark/fs/bench-rmdirSync.js @@ -37,6 +37,6 @@ function main({ n, type }) { break; } default: - new Error('Invalid type'); + throw new Error('Invalid type'); } } diff --git a/benchmark/fs/bench-symlinkSync.js b/benchmark/fs/bench-symlinkSync.js index 92ceb3579a42..c8864527463a 100644 --- a/benchmark/fs/bench-symlinkSync.js +++ b/benchmark/fs/bench-symlinkSync.js @@ -46,6 +46,6 @@ function main({ n, type }) { break; } default: - new Error('Invalid type'); + throw new Error('Invalid type'); } } diff --git a/benchmark/fs/bench-timesSync.js b/benchmark/fs/bench-timesSync.js index 8ea879a63ef9..09d5a3891c0b 100644 --- a/benchmark/fs/bench-timesSync.js +++ b/benchmark/fs/bench-timesSync.js @@ -56,6 +56,6 @@ function main({ n, type, func }) { break; } default: - new Error('Invalid type'); + throw new Error('Invalid type'); } } diff --git a/benchmark/fs/bench-unlinkSync.js b/benchmark/fs/bench-unlinkSync.js index 8b992198c8d3..9b134aa678c5 100644 --- a/benchmark/fs/bench-unlinkSync.js +++ b/benchmark/fs/bench-unlinkSync.js @@ -28,7 +28,7 @@ function main({ n, type }) { files = new Array(n).fill(tmpdir.resolve(`.non-existing-file-${Date.now()}`)); break; default: - new Error('Invalid type'); + throw new Error('Invalid type'); } bench.start(); diff --git a/benchmark/fs/bench_fdatasyncSync.js b/benchmark/fs/bench_fdatasyncSync.js index 9aedb0a314fb..cd6babadeeeb 100644 --- a/benchmark/fs/bench_fdatasyncSync.js +++ b/benchmark/fs/bench_fdatasyncSync.js @@ -24,7 +24,7 @@ function main({ n, type }) { fd = 1 << 30; break; default: - new Error('Invalid type'); + throw new Error('Invalid type'); } bench.start(); diff --git a/benchmark/webstorage/getItem.js b/benchmark/webstorage/getItem.js index f92ee0318ff6..b82960a6f489 100644 --- a/benchmark/webstorage/getItem.js +++ b/benchmark/webstorage/getItem.js @@ -70,6 +70,6 @@ function main({ n, type }) { bench.end(n); break; default: - new Error('Invalid type'); + throw new Error('Invalid type'); } } diff --git a/benchmark/webstorage/removeItem.js b/benchmark/webstorage/removeItem.js index 0de686d45a3d..738ae8a24262 100644 --- a/benchmark/webstorage/removeItem.js +++ b/benchmark/webstorage/removeItem.js @@ -70,6 +70,6 @@ function main({ n, type }) { bench.end(n); break; default: - new Error('Invalid type'); + throw new Error('Invalid type'); } } diff --git a/benchmark/webstorage/setItem.js b/benchmark/webstorage/setItem.js index 5d88a39ef52a..fa53bab20df6 100644 --- a/benchmark/webstorage/setItem.js +++ b/benchmark/webstorage/setItem.js @@ -58,6 +58,6 @@ function main({ n, type }) { bench.end(n); break; default: - new Error('Invalid type'); + throw new Error('Invalid type'); } } From 2c08205011c6899c96a584073f697a1cef66ac59 Mon Sep 17 00:00:00 2001 From: Minho Yoo <13810291+irontaek@users.noreply.github.com> Date: Wed, 14 Oct 2026 00:08:11 +0900 Subject: [PATCH 2/2] tools: disallow constructing an Error without using it Add a no-restricted-syntax selector next to the existing ThrowStatement one. It would have caught the benchmark bug fixed in the previous commit; the two intentional sites are disabled inline. Assisted-by: a closed-source coding agent Signed-off-by: Minho Yoo <13810291+irontaek@users.noreply.github.com> --- benchmark/error/error.js | 1 + test/parallel/test-errors-systemerror.js | 1 + tools/eslint/eslint.config_utils.mjs | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/benchmark/error/error.js b/benchmark/error/error.js index c856f3e07f6b..b4b5292d0412 100644 --- a/benchmark/error/error.js +++ b/benchmark/error/error.js @@ -9,6 +9,7 @@ const bench = common.createBenchmark(main, { function main({ n }) { bench.start(); for (let i = 0; i < n; ++i) + // eslint-disable-next-line no-restricted-syntax new Error('test'); bench.end(n); } diff --git a/test/parallel/test-errors-systemerror.js b/test/parallel/test-errors-systemerror.js index 629a3d1c0869..651e7f8d8962 100644 --- a/test/parallel/test-errors-systemerror.js +++ b/test/parallel/test-errors-systemerror.js @@ -7,6 +7,7 @@ const { E, SystemError, codes, kIsNodeError } = require('internal/errors'); const { inspect } = require('internal/util/inspect'); assert.throws( + // eslint-disable-next-line no-restricted-syntax () => { new SystemError(); }, { name: 'TypeError', diff --git a/tools/eslint/eslint.config_utils.mjs b/tools/eslint/eslint.config_utils.mjs index 7b09047937bf..e6008c457935 100644 --- a/tools/eslint/eslint.config_utils.mjs +++ b/tools/eslint/eslint.config_utils.mjs @@ -16,6 +16,10 @@ export const noRestrictedSyntaxCommonAll = [ selector: 'ThrowStatement > CallExpression[callee.name=/Error$/]', message: 'Use `new` keyword when throwing an `Error`.', }, + { + selector: 'ExpressionStatement > NewExpression[callee.name=/Error$/]', + message: 'Throw, return, or assign the `Error`; constructing it alone does nothing.', + }, { selector: "CallExpression[callee.property.name='substr']", message: 'Use String.prototype.slice() or String.prototype.substring() instead of String.prototype.substr()',