[BUG] WSL: OSC 8 file:/// hyperlinks can never be opened — Windows cannot resolve a Linux path
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
Under WSL, Claude Code builds the OSC 8 target for file paths withpathToFileURL(), producing file:///home/<user>/... — a Linux path.
The terminal hands that URI to Windows via ShellExecuteW, and Windows has no
idea what /home/<user> means. Nothing happens on Ctrl+Click. Ever.
The paths render and highlight on hover, so they look clickable. They just
aren't.
This is not the VS Code problem from #18717 (macOS, microsoft/vscode#242371).
It is a plain URI-format bug and it affects every WSL user, in any Windows
terminal. #22748 reported the same thing for WSL + VS Code Remote and was
auto-closed as a duplicate of #18717, which is itself closed as stale — so the
WSL case is currently tracked nowhere.
Evidence
Measured on Windows Terminal 1.24.11911.0, WSL2 Ubuntu, Claude Code 2.1.227.
Each URI passed to ShellExecuteW(NULL, "open", uri, NULL, "C:\\", SW_NORMAL),
which is exactly what the terminal does on Ctrl+Click:
| URI | Result |
|---|---|
| file:///home/user/notes.md — what Claude Code emits | fails, code 2 (ERROR_FILE_NOT_FOUND) |
| file://wsl.localhost/Ubuntu/home/user/notes.md | opens correctly |
| file:///C:/Users/Example/ | opens (code 42) |
| https://example.com/ | opens |
Clicking the same four links in the terminal reproduces this exactly.
One extra data point that rules out the obvious workaround: a drive-less
URI does not resolve against C: either. file:///Users/Example/ fails even
though the corresponding C:\Users\Example directory exists, and creating a
symlink C:\home -> \\wsl.localhost\Ubuntu\home does not help — ShellExecuteW
still returns code 2 with that symlink in place. So there is no user-side fix;
the URI itself has to change.
What Should Happen?
When running under WSL, emit the UNC form that Windows can actually resolve:
file://wsl.localhost/${WSL_DISTRO_NAME}${absolutePath}
Detection is straightforward — WSL_DISTRO_NAME is set, and /proc/version
contains microsoft. Row 2 of the table above confirms this form works today,
with no configuration on the user's side.
Steps to Reproduce
- Run Claude Code in WSL from Windows Terminal.
- Ask it to read or edit any file, so a file path appears in the output.
- Hover the path — it highlights, so the OSC 8 link is being emitted.
- Ctrl+Click it. Nothing happens.
Without Claude Code, the same contrast:
# Fails silently:
printf '\e]8;;file:///home/%s/test.txt\e\\test.txt\e]8;;\e\\\n' "$USER"
# Opens:
printf '\e]8;;file://wsl.localhost/%s/home/%s/test.txt\e\\test.txt\e]8;;\e\\\n' \
"$WSL_DISTRO_NAME" "$USER"
Is this a regression?
Yes. Before the OSC 8 file links were introduced in 2.1.x, paths were plain
text, and terminals that recognise paths themselves handled them correctly.
The explicit URI now overrides that path detection — same mechanism as #18717,
different cause.
Claude Code Version
2.1.227
Operating System
Windows 11 + WSL2 (Ubuntu)
Terminal/Shell
Windows Terminal 1.24.11911.0, zsh, inside tmux 3.4
Additional Information
FORCE_HYPERLINK=0 is not a workaround here: Windows Terminal linkifies URLs
but not file paths, so disabling OSC 8 leaves the paths entirely inert.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗