This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Junction/symbolic folder access error on Windows 11
Type: behavior Stage: resolved
Components: Windows Versions: Python 3.10, Python 3.9
process
Status: closed Resolution: third party
Dependencies: Superseder:
Assigned To: Nosy List: eryksun, fstorino, paul.moore, steve.dower, terry.reedy, tim.golden, zach.ware
Priority: normal Keywords:

Created on 2021-11-04 10:57 by fstorino, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (6)
msg405677 - (view) Author: Fabio Storino (fstorino) Date: 2021-11-04 10:57
After upgrading to Windows 11 I can't run Python scripts from a junction folder anymore. Everything else works as before on that folder.

Background: I have Minecraft installed on a second volume (E:\Games\Minecraft). I created a junction folder at %appdata%\.minecraft pointing to that folder. When I try to run a Python script from that folder I get this error:

---
python: can't open file 'C:\Users\xxxxx\AppData\Roaming\.minecraft\test.py': [Errno 22] Invalid argument
---

When trying to debug in VS Code, I get a more detailed error:

---
Traceback (most recent call last):
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.2032.0_x64
    __qbz5n2kfra8p0\lib\ntpath.py", line 647, in realpath
    path = _getfinalpathname(path)
OSError: [WinError 649] The create operation failed because the name
    contained at least one mount point which resolves to a volume to
    which the specified device object is not attached:
    'c:\\Users\\xxxxx\\AppData\\Roaming\\.minecraft'
---

When trying to open that junction folder in Python's IDLE I get the following error message:

---
[Window Title] Location is not available

[Content] C:\Users\xxxxx\AppData\Roaming\.minecraft is not accessible.

The create operation failed because the name contained at least one
mount point which resolves to a volume to which the specified device
object is not attached.
---

I tried creating a symbolic directory link instead of a junction, but got the same message.

I can run the same scripts directly from the target folder (E:\Games\Minecraft).

I can also run them from the junction folder from an Ubuntu terminal on WSL2 (Windows Subsystem for Linux).

I tried this with Python 3.9 and 3.10 (WSL2 uses Python 3.8).
msg405743 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2021-11-04 18:36
It's not completely surprising that attempting to traverse a name-surrogate reparse point under "%UserProfile%\AppData" fails when using the store app. If you can't or won't move the mountpoint up to %UserProfile%, or anywhere else outside of the application-data tree, then I suggest using a regular Python installation from python.org.

The error in Windows 11 is ERROR_MOUNT_POINT_NOT_RESOLVED (649), based on the NT status code STATUS_MOUNT_POINT_NOT_RESOLVED. This error status is associated with the kernel routines IoCreateFileSpecifyDeviceObjectHint() [1] and IoCreateFileEx() [2]:

    IoCreateFileEx returns this status value if the DriverContext
    parameter is not NULL and if the file or directory name contains
    a mount point that resolves to a volume other than the one to
    which the specified device object is attached. This device 
    object is specified by the DeviceObjectHint member of the 
    IO_DRIVER_CREATE_CONTEXT structure.

A filter driver can use this feature to open a path on a particular volume or filesystem device (i.e. the device hint) and bypass other filter drivers that are attached to the device stack. However, if path parsing traverses a reparse point to another filesystem, it has to fail with STATUS_MOUNT_POINT_NOT_RESOLVED. Note that a reparse point that targets a path in the same filesystem works fine. For example:

    >>> path = os.path.join(os.environ['appdata'], 'spam')
    >>> os.lstat(path).st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT
    True
    >>> os.path.realpath(path)
    'C:\\Temp\\spam'
    >>> os.path.exists(os.path.join(path, 'eggs.py'))
    True
    >>> subprocess.call(['python', os.path.join(path, 'eggs.py')])
    works fine
    0

The case of a cross-device mountpoint or symlink under "%UserProfile%\AppData" also fails when using the store app in Windows 10. However, the error in Windows 10 is ERROR_INVALID_FUNCTION (1), from the status code STATUS_NOT_IMPLEMENTED, so the underlying implementation details must be quite different. I was able to work around the limitation somewhat in Windows 10 (but not Windows 11) by first changing to the mountpoint directory and accessing relative paths. This doesn't work when running a script, however, since the interpreter tries to open the fully-qualified path, which has to traverse the mountpoint or symlink.

---
[1 https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-iocreatefilespecifydeviceobjecthint
[2] https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-iocreatefileex.
msg405838 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2021-11-06 01:28
Eryk, does this or does this not look to you like a bug in CPython?  I don't know enough to tell.
msg405848 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2021-11-06 06:46
> does this or does this not look to you like a bug in CPython?

It's better to leave the detailed explanation of limits up to the document that's referenced for further information [1], but this issue isn't even briefly mentioned there. Maybe it would help some people to mention the store package's [2] limitation on using reparse points in "%UserProfile%\AppData", but this is the first I've seen of this issue, and I hadn't even considered the problem beforehand. I don't see why it would ever be necessary to use a cross-volume reparse point in the application-data tree.

Also, maybe this is a bug in the operation system that could get fixed in the future. It could be unintended behavior in the filesystem filter that virtualizes access to "%UserProfile%\AppData". Maybe someone used a target device hint as a convenience in the design, without thinking about how it would limit the resolution of reparse points. 

---
[1] https://docs.microsoft.com/en-us/windows/msix/desktop/desktop-to-uwp-behind-the-scenes
[2] https://docs.python.org/3.10/using/windows.html#the-microsoft-store-package
msg405905 - (view) Author: Fabio Storino (fstorino) Date: 2021-11-07 14:06
Hello, Eryk. Just to let you know that a regular Python installation was able to access my junction folder in AppData and run scripts there.

Thank you for the information on how store apps handle reads/writes in the AppData folder.

This is my first bug report. Should I mark this issue as closed?
msg405909 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2021-11-07 16:47
All we can do here is document the store app's limitation on cross-volume reparse points (junctions, symlinks) in "%UserProfile%\AppData". I suppose it's a rare enough problem that it can just be closed as a third-party issue.
History
Date User Action Args
2022-04-11 14:59:52adminsetgithub: 89873
2021-11-07 16:47:47eryksunsetstatus: open -> closed
resolution: works for me -> third party
messages: + msg405909

stage: resolved
2021-11-07 14:06:21fstorinosetresolution: works for me
messages: + msg405905
2021-11-06 06:46:14eryksunsetmessages: + msg405848
2021-11-06 01:28:01terry.reedysetnosy: + terry.reedy
messages: + msg405838
2021-11-04 18:36:09eryksunsetnosy: + eryksun
messages: + msg405743
2021-11-04 10:57:57fstorinocreate