From 71936e7bb4cd9b34312ef8130c1ecd7d44e2282f Mon Sep 17 00:00:00 2001 From: Archkon <180910180+Archkon@users.noreply.github.com> Date: Sat, 1 Aug 2026 18:22:57 +0800 Subject: [PATCH] src: avoid task runner crash on inaccessible bin paths Use the error_code overload of std::filesystem::is_directory() when probing node_modules/.bin, allowing package.json lookup to continue when the directory cannot be accessed. Signed-off-by: Archkon <180910180+Archkon@users.noreply.github.com> --- src/node_task_runner.cc | 3 ++- test/parallel/test-node-run.js | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/node_task_runner.cc b/src/node_task_runner.cc index 2b3e005abf34..b3f3fddb4152 100644 --- a/src/node_task_runner.cc +++ b/src/node_task_runner.cc @@ -227,7 +227,8 @@ FindPackageJson(const std::filesystem::path& cwd) { directory_path = directory_path.parent_path()) { // Append "path/node_modules/.bin" to the env var, if it is a directory. auto node_modules_bin = directory_path / "node_modules" / ".bin"; - if (std::filesystem::is_directory(node_modules_bin)) { + std::error_code error; + if (std::filesystem::is_directory(node_modules_bin, error)) { path_env_var += ConvertPathToUTF8(node_modules_bin) + env_var_separator; } diff --git a/test/parallel/test-node-run.js b/test/parallel/test-node-run.js index 7c1f6609f6f1..f4e448b46769 100644 --- a/test/parallel/test-node-run.js +++ b/test/parallel/test-node-run.js @@ -243,6 +243,33 @@ describe('node --run [command]', () => { assert.strictEqual(output.path.split(path.delimiter)[0], nodeModulesBin); }); + it('skips inaccessible node_modules directories', { + skip: common.isWindows || common.isIBMi || process.getuid?.() === 0, + }, async () => { + tmpdir.refresh(); + const nodeModules = tmpdir.resolve('node_modules'); + fs.mkdirSync(nodeModules); + fs.writeFileSync(tmpdir.resolve('package.json'), JSON.stringify({ + scripts: { test: 'echo ok' }, + })); + fs.chmodSync(nodeModules, 0o000); + + let child; + try { + child = await common.spawnPromisified( + process.execPath, + [ '--run', 'test'], + { cwd: tmpdir.path }, + ); + } finally { + fs.chmodSync(nodeModules, 0o700); + } + + assert.strictEqual(child.stdout, 'ok\n'); + assert.strictEqual(child.stderr, ''); + assert.strictEqual(child.code, 0); + }); + it('returns error on unparsable file', async () => { const child = await common.spawnPromisified( process.execPath,