Repository: node
Issue: lstat unknown error - no useful error number/code displayed?
Labels: fs

### Version

v16.14.2

### Platform

Microsoft Windows NT 10.0.19044.0 x64

### Subsystem

fs

### What steps will reproduce the bug?

1. Corrupt a file at a low level, I think this needs to be down to the NTFS level.
2. Begin an operation that causes `node` to invoke `lstat` on one of the corrupted files. For me specifically, this was a yarn operation.

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

Intermittently (depends on file corruption), or constantly if the files remain corrupted. Because of [Issue #34817](https://github.com/nodejs/node/issues/34817), there is no useful stacktrace, so it's hard to say what operation specifically invokes the failing call.

### What is the expected behavior?

Show the error code so a developer can debug the issue.

### What do you see instead?

`Error: UNKNOWN: unknown error, lstat 'C:\Users\Lucius Riccio\AppData\Local\Yarn\Data\global\node_modules\es-abstract\2022\GetV.js'`

### Additional information

As someone who's only mildly familiar with libuv, and barely familiar with node's C++ architecture, this was very hard to understand.

The first clue I had came while trying to figure out what the error was. I had to trace it in procmon to do that. The offending event was an `IRP_MJ_CREATE` (generated by `NtCreateFile` up the stack) that failed with a result that procmon called `FILE CORRUPT`. I believe this refers to a `0xC0000102`/`STATUS_FILE_CORRUPT_ERROR` NTSTATUS code. It would be useful to show this, but I'll come back to that later.

As best as I can tell, the node entry point/bridge from js to native for lstat [is `LStat`, here](https://github.com/nodejs/node/blob/5fad0b93667ffc6e4def52996b9529ac99b26319/src/node_file.cc#L1064).

As best as I can tell, the `Error: UNKNOWN: unknown error, lstat` comes from [`UVException`/`hideStackFrames`](https://github.com/nodejs/node/blob/5fad0b93667ffc6e4def52996b9529ac99b26319/lib/internal/errors.js#L493), which uses the `uv_fs_t* req` [result field](https://github.com/nodejs/node/blob/5fad0b93667ffc6e4def52996b9529ac99b26319/deps/uv/include/uv.h#L1335) to [translate the error code](https://github.com/nodejs/node/blob/5fad0b93667ffc6e4def52996b9529ac99b26319/deps/uv/src/win/error.c#L66).

The reason I'm filing this bug is that it *looks* like libuv has a way to get the underlying error code out ([through `SET_REQ_WIN32_ERROR`](https://github.com/nodejs/node/blob/5fad0b93667ffc6e4def52996b9529ac99b26319/deps/uv/src/win/fs.c#L79)) even if it's not a known error code. I think that `uv_fs_lstat` returns the translated error, but also stuffs the system errno in [the private `DWORD` `req->sys_errno_`](https://github.com/nodejs/node/blob/5fad0b93667ffc6e4def52996b9529ac99b26319/deps/uv/include/uv/win.h#L618).

For reference, it's a classic C-like data-hiding/pseudoinheritance paradigm going on, the `uv_fs_t` contains a [`UV_FS_PRIVATE_FIELDS` macro defining fields](https://github.com/nodejs/node/blob/5fad0b93667ffc6e4def52996b9529ac99b26319/deps/uv/include/uv.h#L1339), and you can find the errno field [here](https://github.com/nodejs/node/blob/5fad0b93667ffc6e4def52996b9529ac99b26319/deps/uv/include/uv/win.h#L618).

There is a *lot* of C++ template magic going on for translating the C++/v8 object to the `uv_fs_t`... it's good stuff, but very hard for me to parse without tons of coffee and several hours. I suspect one option, though would be to modify it to read from the libuv private fields that contain `sys_errno_`, then modify [`handleErrorFromBinding`](https://github.com/nodejs/node/blob/5fad0b93667ffc6e4def52996b9529ac99b26319/lib/internal/fs/utils.js#L343) to also dump the underlying error code to stdout if `req->result` is [`UV_UNKNOWN`](https://github.com/nodejs/node/blob/5fad0b93667ffc6e4def52996b9529ac99b26319/deps/uv/src/win/error.c#L171). This would be ugly of course, inspecting private fields, but it would give much more useful information to the developer who's seeing things break in mysterious way. If I had the error code that libuv got I could file an issue there to add it to their error map - `STATUS_FILE_CORRUPT_ERROR` is a guess because procmon doesn't seem to translate it properly :) This is an ugly, platform-specific hack, but it would be better than nothing IMO.

I tried to be as thorough as possible in outlining the problematic path despite not having a drop-in repro, and I hope I provided enough info on my proposed fix. 

There are a few related issues in node, and around github:

- https://github.com/nodejs/node/issues/33024
- https://github.com/nodejs/node/issues/34817 (mentioned above)
- https://github.com/microsoft/vscode-python/issues/10233 - search the page for `unknown: unknown` and you will see twenty instances of this in [this comment](https://github.com/microsoft/vscode-python/issues/10233#issuecomment-592684432).


Now I will go and see if deleting the files OR a chkdsk works around the problem for me!