The Windows drives WSL2 cannot reach: Google Drive returns ENODEV, mapped network drives are simply absent
Symptom
I needed a report out of a Google Drive folder from inside WSL2. The drive letter exists in Windows, the mount exists in Linux, and every single access fails:
$ ls /mnt/g
ls: reading directory '/mnt/g': No such device
$ stat /mnt/g
stat: cannot statx '/mnt/g': No such device
From Python the same thing reads as os error 19:
OSError: [Errno 19] No such device: '/mnt/g'
At the exact same moment /mnt/c, /mnt/d and /mnt/e list normally. Windows interop works. Nothing else
is broken. And the mount is there — it looks indistinguishable from a working one:
$ grep drvfs /proc/mounts
C:\134 /mnt/c 9p rw,dirsync,noatime,aname=drvfs;path=C:\;uid=1000;gid=1000;symlinkroot=/mnt/ 0 0
G:\134 /mnt/g 9p rw,dirsync,noatime,aname=drvfs;path=G:\;uid=1000;gid=1000;symlinkroot=/mnt/ 0 0
The second half of the same afternoon produced a different failure on a different letter. A drive letter
mapped to a file server — call it P: — does not fail at all. It is not there:
$ ls /mnt/p
$ grep ' /mnt/p ' /proc/mounts
$
No error, no entry in the mount table, just an empty directory. WSL2 auto-mounts local Windows volumes. A
network mapping is not a volume, it is a per-user Windows session artefact, so nothing ever gets mounted and
/mnt/p stays the empty stub automount created.
What it is not
The first thing anyone who has used WSL2 for a while will reach for is wsl --shutdown, because there is a
well-known failure where all the /mnt mounts die at once. That is
the suspend/resume case, and it is a different
animal in three respects:
- it reports
Input/output error, os error 5, notNo such device; - it takes out
C:,D:andE:together, not one lone letter; - it kills Windows interop too, because
cmd.exeandwsl.exelive under/mnt/c.
Only that one is fixed by running wsl --shutdown from Windows. For the Google Drive letter, restarting the
utility VM changed nothing at all: the mount came back, still listed in /proc/mounts, still returning
errno 19 on the first ls. I paid the VM restart twice before accepting that.
So read the errno before reaching for a remedy. os error 5 on every drive plus dead interop is a dead 9p
transport. os error 19 on one cloud-sync letter, while /mnt/c still lists fine, means the transport is
healthy enough to answer — and its answer is that there is no device to open. It is not a permissions
problem either: EACCES prints Permission denied, and no automount option conjures a missing device.
What I measured
The diagnosis fits in one command, and it is deliberately not the Windows-side one:
grep drvfs /proc/mounts
ls /mnt/p
The /proc/mounts read is instant and local to the guest. The tempting alternatives — net use and
wmic logicaldisk get name,providername through interop — are a trap during triage: when a mapped drive is
disconnected, both can block for tens of seconds while Windows retries the share. I burned time staring at a
hung net use before switching to reading the mount table, which tells you everything you need in one line
per drive.
That gives a three-way decision:
| Observation | Case | What actually helps |
|---|---|---|
| entry present, I/O returns errno 5, interop dead | dead 9p transport (suspend/resume) | wsl --shutdown from Windows |
| entry present, I/O returns errno 19, other drives fine | virtual cloud-filter filesystem, not a real volume | mirror the data onto C:, or copy via PowerShell |
no entry, /mnt/x empty | never mounted — network mapping or unsupported provider | mount the share from Linux yourself |
To confirm the middle case from the Windows side, Get-PSDrive -PSProvider FileSystem is worth one call: it
lists what Windows itself can see, which for G: is a provider-backed drive rather than an ordinary fixed
volume.
The cause
Google Drive for Desktop in streaming mode does not put a filesystem on a disk. It registers a virtual
namespace through the Windows cloud-files mechanism, so G:\ is served by a filter driver that materialises
file contents on demand from the network. From Explorer this is transparent. From WSL2 it is not: drvfs
knows how to proxy a normal Windows volume over 9p, and it cannot open a provider-backed virtual drive at
all. The mount entry gets created because the letter exists; every I/O against it is rejected by the device
layer underneath, which is exactly what ENODEV means.
Workaround: go through interop, not through the mount
Both the streaming drive and the mapped network drive are fully reachable from Windows. So stop asking Linux
to read them and ask Windows to copy them somewhere Linux can read — C:, which is a real volume.
cd /mnt/c
powershell.exe -NoProfile -Command 'Copy-Item "G:\My Drive\report" "C:\Temp\report" -Recurse -Force'
ls /mnt/c/Temp/report
Three details in there matter and each one cost me an attempt:
cd /mnt/c first. Launching a Windows binary while your working directory is on the Linux filesystem
makes interop complain — Windows has no path for /home/..., so you get a warning about the current
directory or an outright failure. Move to a Windows-visible directory before the call.
powershell.exe, not cmd.exe. These paths contain spaces and backslashes; cmd.exe responds with a
syntax error rather than copying anything. PowerShell’s quoting handles "G:\My Drive\..." as written, and
it gives you Test-Path to check the destination before copying:
powershell.exe -NoProfile -Command 'Test-Path "C:\Temp"'
It works in the other direction too. The same call with the arguments reversed writes onto a mapped network drive that WSL2 cannot see, because the mapping belongs to the Windows session that PowerShell runs in.
One sharp edge that has no workaround at this level: Google-native documents are not documents. A .gform,
.gsheet or .gdoc is a 171-byte shortcut file pointing at the online original. Copy-Item throws an
IOException on them, and even if it did not, there would be nothing inside worth copying. Exporting those
means the Drive API or a manual download from the browser — no filesystem operation will do it.
The permanent fix
For Google Drive, switch the folders you actually work with from streaming to “Mirror files” in the
Drive for Desktop preferences. Mirrored folders are kept as ordinary files on a real local volume — by
default under your Windows user profile — so they arrive at a plain /mnt/c/... path and behave like any
other Windows path from WSL2. No interop, no copy step, no errno 19. The cost is disk space for the
mirrored subtree, which is why it is worth doing per folder rather than for the whole drive.
For the mapped network drive, the equivalent is to stop borrowing Windows’ mapping and mount the share from Linux directly:
sudo mount -t cifs //nas.example.lan/share /mnt/share -o username=user,uid=1000,gid=1000
Now the share is a first-class Linux mount, independent of whether Windows happens to have a letter for it, and it survives the Windows session logging out from under you.
What to remember
A mount table is a record of intent, not a health check. /proc/mounts told me WSL2 had been asked to
expose G:\ over 9p and had built the object to do it. It said nothing about whether the Windows side could
answer a read, and for a cloud-filter drive nothing can. The entry and the capability are two separate
facts, and only one of them shows up in the mount table.
The errno is the cheapest diagnostic available and the one people skip — ls prints the message, everyone
reads the words, nobody reads the number. Here the number picks the remedy: 5 means a transport that was
alive and died, so restart it; 19 means a device that was never openable, so move the data instead of
retrying; nothing at all means no mount was attempted, so create it yourself.
The habit that follows: when a Windows path misbehaves in WSL2, decide first whether you are looking at a
real volume. Local disks are real, and so are mirrored cloud folders, because they are ordinary files on
C:. Streaming cloud drives and session-scoped network mappings are not, and no mount-option tuning will
make drvfs treat them as if they were.