Skip to content

ENOENT error when reading root of subst drive on Windows #58970

Description

@PetSerAl

Version

v24.3.0

Platform

Microsoft Windows NT 10.0.26100.0 x64

Subsystem

No response

What steps will reproduce the bug?

md Subst
echo test>Subst\testfile
subst M: Subst
fs.readdirSync("C:\\")
fs.readdirSync("M:\\")
fs.readdirSync("M:\\.")
Image

How often does it reproduce? Is there a required condition?

Always

What is the expected behavior? Why is that the expected behavior?

No error should happens.

What do you see instead?

ENOENT: no such file or directory, scandir 'M:\\'

Additional information

Not program with Node.js myself. Have issue with this behavior with VS Code extension belav/csharpier#1637

Activity

  1. added
    windowsIssues and PRs related to the Windows platform.
    libuvIssues and PRs related to the libuv dependency or the uv binding.
    on Jul 6, 2025
  2. juanarbol commented on Jul 6, 2025

    @juanarbol
    Member

    Hi, thanks for your report; just by doing some search in libuv, that's a known issue. I'm not a windows API programmer, at all. Not sure if there is much we can do from our side, for now, I'll just ping @nodejs/libuv; from what I see, I think it is easier to report this bug and suggest to your extension vendor that uses the extra . char.

    I think it is because of fs__capture_path, but I'm not sure. Again, it's a known issue, and many fs calls in windows "invokes" fs__capture_path, just like uv_fs_realpath (the libuv call with caveats)

    Refs:

  3. PetSerAl commented on Jul 6, 2025

    @PetSerAl
    Author

    @juanarbol Issue you pointed to libuv/libuv#1877 was closed as stale on Aug 10, 2019. While this error not reproduced with v20.19.3 (v20 first released Apr 18, 2023), nor with v21.7.3, but reproduced with v22.17.0. So this is more resent change in behavior.

    Image
  4. PetSerAl commented on Jul 6, 2025

    @PetSerAl
    Author

    That is as much, as I can investigate this (echo y|cacls Subst /s:D:P is to remove all permissions from directory to force error message):
    Image
    As you can see fs.readdirSync("M:\\") in v22 case produce different error message: ENOENT: no such file or directory, scandir 'M:\\' instead of EPERM: operation not permitted, scandir 'M:\'. Notice double backslash in the end of path.
    As I mention in my comment to original issue, I think it is what causing the issue:
    Image

    So in v22 (compared to v20) it was changed how paths normalized and M:\ now normalized to M:\\, which is incorrect behavior.

  5. PetSerAl commented on Jul 7, 2025

    @PetSerAl
    Author

    I think issue is here:

    node/src/node_file.cc

    Lines 1966 to 1987 in 1effb26

    #ifdef _WIN32
    // On Windows, some API functions accept paths with trailing slashes,
    // while others do not. This code checks if the input path ends with
    // a slash (either '/' or '\\') and, if so, ensures that the processed
    // path also ends with a trailing backslash ('\\').
    bool slashCheck = false;
    if (path.ToStringView().ends_with("/") ||
    path.ToStringView().ends_with("\\")) {
    slashCheck = true;
    }
    #endif
    ToNamespacedPath(env, &path);
    #ifdef _WIN32
    if (slashCheck) {
    size_t new_length = path.length() + 1;
    path.AllocateSufficientStorage(new_length + 1);
    path.SetLengthAndZeroTerminate(new_length);
    path.out()[new_length - 1] = '\\';
    }
    #endif

    As M:\ ends with backslash, then slashCheck will be true. And second #ifdef _WIN32 seems to expect that ToNamespacedPath newer return path, which ends with backslash (which likely incorrect for M:\ as input), and adds backslash regardless of path content. That cause incorrect transformation M:\ to M:\\.

  6. juanarbol commented on Jul 7, 2025

    @juanarbol
    Member

    will you send a PR?

  7. PetSerAl commented on Jul 8, 2025

    @PetSerAl
    Author

    Not anytime soon. I do not really that familiar with C++, and currently do not have necessary tooling to build and test my changes.

  8. bpasero commented on Jul 8, 2025

    @bpasero
    Contributor

    Can confirm this IS a regression between node.js 20 and 22, as reported by users in VS Code (that recently updated to node.js 22).

    With a subst drive (subst T: C:\<some folder>)

    node.js 22:

    C:\GitDevelopment\vscode>node
    Welcome to Node.js v22.17.0.
    Type ".help" for more information.
    > fs.readdirSync("T:\\")
    Uncaught Error: ENOENT: no such file or directory, scandir 'T:\\'
        at Object.readdirSync (node:fs:1583:26) {
      errno: -4058,
      code: 'ENOENT',
      syscall: 'scandir',
      path: 'T:\\\\'
    }
    

    node.js 20:

    C:\Users\bpasero\Downloads>node
    Welcome to Node.js v20.9.0.
    Type ".help" for more information.
    > fs.readdirSync("T:\\")
    [
      'CHANGELOG.md',
      'package.json',
      'README.md',
      'super',
      'test.ps1',
      'tsconfig.json',
      'vsc-extension-quickstart.md',
      'yarn.lock'
    ]
    
  9. PetSerAl commented on Jan 5, 2026

    @PetSerAl
    Author

    No longer reproduced on v24.12.0 and v25.2.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    libuvIssues and PRs related to the libuv dependency or the uv binding.windowsIssues and PRs related to the Windows platform.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions