By Yarden Shafir

Did you know that symbolic links (or symlinks) created through Windows Subsystem for Linux (WSL) can’t be followed by Windows?

I recently encountered this rather frustrating issue as I’ve been using WSL for my everyday work over the last few months. No doubt others have noticed it as well, so I wanted to document it for anyone who may be seeking answers.

Let’s look at an example of the issue. I’ll use Ubuntu as my Linux client with WSL2 and create a file followed by a symlink to a file in the same directory (via ln -s):

echo "this is a symlink test" > test_symlink.txt
ln -s test_symlink.txt targetfile.txt

In WSL, I can easily read both the original file (test_symlink.txt) and the symlink (targetfile.txt). But when I try to open the symlink from the Windows file explorer, an error occurs:

The Windows file explorer error

The same error occurs when I try to access targetfile.txt from the command line:

The command line error

Looking at the directory, I can see the target file, but it has a size of 0 KB:

The symlink in the directory with a size of 0 KB

And when I run dir, I can see that Windows recognizes targetfile.txt as an NTFS junction but can’t find where the link points to, like it would for a native Windows symlink:

Windows can’t find where the link points to.

When I asked about this behavior on Twitter, Bill Demirkapi had an answer—the link that is created by WSL is an “LX symlink,” which isn’t recognized by Windows. That’s because symlinks on Linux are implemented differently than symlinks on Windows: on Windows, a symlink is an object, implemented and interpreted by the kernel. On Linux, a symlink is simply a file with a special flag, whose content is a path to the destination. The path doesn’t even have to be valid!

Using FileTest, we can easily verify that this is a Linux symlink, not a Windows link. If you look carefully, you can even see the path to the destination file in the file’s DataBuffer:

FileTest verifies the link as a Linux symlink.

FileTest can also provide a more specific error message regarding the file open failure:

FileTest’s file open failure error message

It turns out that trying to open this file with NtCreateFile fails with an STATUS_IO_REPARSE_TAG_NOT_HANDLED error, meaning that Windows recognizes this file as a reparse point but can’t identify the LX symlink tag and can’t follow it. Windows knows how to handle some parts of the Linux filesystem, as explained by Microsoft, but that doesn’t include the Linux symlink format.

If I go back to WSL, the symlink works just fine—the system can see the symlink target and open the file as expected:

The symlink works in WSL.

It’s interesting to note that symlinks created on Windows work normally on WSL. I can create a new file in the same directory and create a symlink for it using the Windows command line (cmd.exe):

echo "this is a test for windows symlink" > test_win_symlink.txt
mklink win_targetfile.txt test_win_symlink.txt

Now Windows treats this as a regular symlink that it can identify and follow:

Windows can follow symlinks created on Windows.

But the Windows symlink works just as well if we access it from within WSL:

The Windows symlink can also be accessed from WSL.

We get the same result if we create a file junction using the Windows command line and try to open it with WSL:

echo "this is a test for windows junctions" > test_win_junction.txt
mklink /J junction_targetfile.txt test_win_junction.txt

This is how the directory now looks from Windows’s point of view:

The directory from Windows’s point of view

And this is how it looks from WSL’s point of view:

The directory from WSL’s point of view

Hard links created by WSL do work normally on Windows, so this issue applies only to symlinks.

To summarize, Windows handles only symlinks that were created by Windows, using its standard tags, and fails to process WSL symlinks of the “LX symlink” type. However, WSL handles both types of symlinks with no issues. If you use Windows and WSL to access the same files, it’s worth paying attention to your symlinks and how they are created to avoid the same issues I ran into.

One last thing to point out is that when Bill Demirkapi tested this behavior, he noticed that Windows could follow WSL’s symlinks when they were created with a relative path but not with an absolute path. On all systems I tested, Windows couldn’t follow any symlinks created by WSL. So there is still some mystery left here to investigate.