Node: ENOENT thrown when trying to create a file with an invalid filename

Created on 9 Oct 2016  Â·  13Comments  Â·  Source: nodejs/node

Node v6.7.0, Windows 10

To reproduce the issue:

fs.writeFileSync('C:\\temp\\foo:bar:baz', 'fail')

Expected output: Some error message about the filename being invalid because it contains colons

Actual output:

Error: ENOENT: no such file or directory, open 'C:\temp\foo:bar:baz'
    at Error (native)
    at Object.fs.openSync (fs.js:640:18)
    at Object.fs.writeFileSync (fs.js:1333:33)
    at repl:1:4
    at sigintHandlersWrap (vm.js:22:35)
    at sigintHandlersWrap (vm.js:96:12)
    at ContextifyScript.Script.runInThisContext (vm.js:21:12)
    at REPLServer.defaultEval (repl.js:313:29)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
blocked fs libuv windows

Most helpful comment

I believe it _might_ be technically possible to provide a better error message since CreateFileW() on Windows probably sets the 'last error' code to ERROR_BAD_PATHNAME in such cases. From what I can tell, the original Windows-specific error code is stored by libuv in such a way that node should have access to it.

All 13 comments

Pretty sure that error codes comes straight from the Windows API, and it even seems consistent with macOS, so I'd lean towards leaving it as-is. Doing a check for filename validity on Windows is costly and should probably be done by the user.

Pretty sure that error codes comes straight from the Windows API

Are you sure? I tried the equivalent in C#:

File.WriteAllText("c:\\temp\\foo:bar:baz", "winning");

And got a better error message:

System.NotSupportedException: The given path's format is not supported.

Or:

System.ArgumentException: Illegal characters in path.

I didn't try raw Win32 API calls though.

So, just in case this is helpful: Colons are used by NTFS to name separate Alternate Data Streams, so if there’s a file named foo, creating foo:bar and writing to it (as an ADS) should work.

So it would seem to me that ENOENT would be the correct code for writing to foo:bar when foo doesn’t exist.

I’m not sure the overhead of checking for multiple colons would be worth it…

I believe it _might_ be technically possible to provide a better error message since CreateFileW() on Windows probably sets the 'last error' code to ERROR_BAD_PATHNAME in such cases. From what I can tell, the original Windows-specific error code is stored by libuv in such a way that node should have access to it.

So it would seem to me that ENOENT would be the correct code for writing to foo:bar when foo doesn’t exist.

Interesting, I didn't know that.

The same error message happens for other invalid characters though, such as question marks:

> fs.writeFileSync('C:\\temp\\foo??', 'fail')
Error: ENOENT: no such file or directory, open 'C:\temp\foo??'
    at Error (native)
    at Object.fs.openSync (fs.js:640:18)
    at Object.fs.writeFileSync (fs.js:1333:33)
    at repl:1:4

The issue here is that libuv maps ERROR_INVALID_NAME to UV_ENOENT here. This particular mapping was added by @piscisaureus way back in 2012.

The question is what it should map to instead. Would UV_EINVAL be better? Understandably, libuv doesn't have a dedicated error code for an invalid file name since Linux doesn't have invalid filenames.

You could change it (major version), but before you do so, do some research into what different "libc" implementations do on windows - at least try what error the open() call in msvcrt produces when you try to create a file with an invalid name, and try cygwin too.

Linux doesn't have invalid filenames.

A / is a invalid character in a filename on all likely all Linux filesystems. The returned error code depends on the location of the / in the filename:

fs.writeFile("invalid/")
// Error: EISDIR: illegal operation on a directory, open 'invalid/'
> fs.writeFile("invalid/file")
// Error: ENOENT: no such file or directory, open 'invalid/file'

@piscisaureus

Good idea. I assume you meant fopen, not open. fopen("foo??", "w") sets errno to EINVAL in both CRT and MSYS2.

@silverwind

In both of your examples, / is interpreted as a path separator. I don't think it's even possible to make Linux interpret it as part of the file name.

Thanks for reporting this issue, I had no idea that : were invalid file name characters in Windows, been debugging an Electron app for a bit now.

Should this issue remain open?

It's going to remain an issue until libuv is upgraded to 2.x.

There's been no activity on this and it's been blocked indefinitely pending the update to libuv 2.x. Keeping the issue open does not benefit anyone but we also don't want to forget about it. I've added it to a Futures project board so it doesn't get lost.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fanjunzhi picture fanjunzhi  Â·  3Comments

loretoparisi picture loretoparisi  Â·  3Comments

srl295 picture srl295  Â·  3Comments

willnwhite picture willnwhite  Â·  3Comments

seishun picture seishun  Â·  3Comments