From 56967616307c7613c45477925743f5e08f3bd2de Mon Sep 17 00:00:00 2001 From: sjwhole Date: Sun, 13 Jul 2025 16:17:06 +0900 Subject: [PATCH] fs: return rejected promise when mkdtemp lacks permissions Previously, fs.promises.mkdtemp() would cause a TypeError "Method Promise.prototype.then called on incompatible receiver undefined" when called without write permissions. This happened because the promise was never returned to JavaScript after being rejected. This commit ensures SetReturnValue() is called before returning from the function, so JavaScript receives a proper rejected promise with an ERR_ACCESS_DENIED error that can be caught and handled. Fixes: https://github.com/nodejs/node/issues/59023 --- src/node_file.cc | 14 +++++++++----- .../test-permission-fs-promises-mkdtemp.js | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 test/parallel/test-permission-fs-promises-mkdtemp.js diff --git a/src/node_file.cc b/src/node_file.cc index 9636e42a9d556d..d7d9f7f63ff179 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -3074,11 +3074,15 @@ static void Mkdtemp(const FunctionCallbackInfo& args) { if (argc > 2) { // mkdtemp(tmpl, encoding, req) FSReqBase* req_wrap_async = GetReqWrap(args, 2); - ASYNC_THROW_IF_INSUFFICIENT_PERMISSIONS( - env, - req_wrap_async, - permission::PermissionScope::kFileSystemWrite, - tmpl.ToStringView()); + if (!env->permission()->is_granted( + env, permission::PermissionScope::kFileSystemWrite, + tmpl.ToStringView())) { + permission::Permission::AsyncThrowAccessDenied( + env, req_wrap_async, permission::PermissionScope::kFileSystemWrite, + tmpl.ToStringView()); + req_wrap_async->SetReturnValue(args); + return; + } FS_ASYNC_TRACE_BEGIN1( UV_FS_MKDTEMP, req_wrap_async, "path", TRACE_STR_COPY(*tmpl)) AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath, diff --git a/test/parallel/test-permission-fs-promises-mkdtemp.js b/test/parallel/test-permission-fs-promises-mkdtemp.js new file mode 100644 index 00000000000000..a20e747b86f982 --- /dev/null +++ b/test/parallel/test-permission-fs-promises-mkdtemp.js @@ -0,0 +1,19 @@ +// Flags: --permission --allow-fs-read=* +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const fs = require('fs'); + +// This test verifies that fs.promises.mkdtemp() returns a proper rejected promise +// when permissions are denied, instead of throwing a TypeError +{ + // Test with simple string path (reproduces the exact issue from GitHub) + assert.rejects( + fs.promises.mkdtemp('test'), + { + code: 'ERR_ACCESS_DENIED', + permission: 'FileSystemWrite', + } + ).then(common.mustCall()); +} \ No newline at end of file