VS Code extension: markdown links to files with non-ASCII names never open (percent-encoded href is never decoded)
Summary
In the VS Code extension's chat panel, clicking a markdown link that points to a file with a
non-ASCII filename does nothing. The link renders and is clickable, but no editor opens and no
error is shown.
This affects any repository whose filenames are not pure ASCII. In my case the entire docs/
tree uses Japanese filenames, so effectively none of Claude's file references are clickable.
Filing as a new issue per the closing message on #65548.
Relationship to existing issues
- #65548 — same defect, same root-cause analysis, reported 2026-06-05 against extension
2.1.161. Auto-closed as not planned on 2026-07-11 for inactivity, with an invitation to
open a new issue if still relevant. It is still relevant: unchanged in 2.1.233.
- #85641 (open) — links never open when the path contains a space. That is the same
missing-decode defect surfacing through %20 instead of %E3%83%90. The one-line fix
below resolves both classes, so the two issues should probably be tracked together.
Environment
| | |
| --- | --- |
| Extension | anthropic.claude-code 2.1.233 (darwin-arm64) |
| Claude Code CLI | 2.1.146 |
| VS Code | 1.133.0 |
| OS | macOS (Darwin 24.6.0), Apple Silicon |
Steps to reproduce
- Create a file with a non-ASCII name, e.g.
docs/バックログ.md - Have Claude reference it as a markdown link:
[バックログ.md](docs/バックログ.md) - Click the link in the chat panel
Expected: the file opens in an editor, as it does for an ASCII-named file.
Actual: nothing happens. No editor, no notification, no entry in the extension output channel.
Root cause
Traced through the shipped bundles in~/.vscode/extensions/anthropic.claude-code-2.1.233-darwin-arm64/.
1. webview/index.js — the markdown renderer percent-encodes the link destination.
Assistant messages are rendered with react-markdown. micromark's URL normalizer percent-encodes
every character with a code point >= 128, so the anchor's href becomes:
docs/50_Development/%E3%83%90%E3%83%83%E3%82%AF%E3%83%AD%E3%82%B0.md
2. The click handler passes that encoded string straight through as a filesystem path.
The anchor's onClick parses the href (the parser accepts it, because it still ends in .md)
and calls fileOpener.open(filePath) without decoding. decodeURI() does not appear anywhere
in the webview bundle, and none of the five decodeURIComponent call sites are on this path.
3. extension.js — openFile() does an existence check on the literal encoded string.
async openFile(e,t){
let r = mi.isAbsolute(e) ? e : mi.join(this.cwd, e);
...
let n = ke.Uri.file(r);
try{ if(Do.statSync(r).isDirectory()){ ... } }catch{}
ke.window.showTextDocument(n).then(...)
}
No file named %E3%83%90....md exists, so showTextDocument is called on a nonexistent URI and
the promise rejects unhandled — which is why the failure is completely silent.
Why the obvious workarounds don't help
- Pre-encoding the path in the markdown source — the normalizer preserves existing valid
%XX sequences, so the href is unchanged and the same failure occurs.
- Using an absolute path — same encoding, same failure.
- Using a
vscode://file/...URL — react-markdown's defaulturlTransformonly permits
http, https, irc, ircs, mailto, xmpp; vscode: is stripped to an empty href.
- Extension settings — the extension contributes 15 settings, none related to link resolution.
The only link form that still works is a link to a directory ([docs/foo/](docs/foo/)),
because directory names happen to be ASCII in my case and openFile() handles directories viarevealInExplorer.
Suggested fix
Decoding in openFile() covers every caller at once. Guarding it on "the decoded path actually
exists" keeps genuine % characters in filenames working:
async openFile(e,t){
try{
if(/%[0-9A-Fa-f]{2}/.test(e)){
let d = decodeURIComponent(e);
let r = mi.isAbsolute(d) ? d : mi.join(this.cwd, d);
if(Do.existsSync(r)) e = d;
}
}catch{}
// ...existing body unchanged
}
I applied exactly this to my local install and it resolves the issue. Verified against:
| Input | Result |
| --- | --- |
| docs/50_Development/%E3%83%90…%B0.md | opens バックログ.md |
| docs/50_Development/バックログ.md (unencoded) | opens, behaviour unchanged |
| /Users/…/260812_%E4%BD%9C…%81%8E.md (absolute) | opens 260812_作業引き継ぎ.md |
| 100%zz_broken.md (real file containing %) | left untouched, opens correctly |
%20 from #85641 takes the same path, so that case is covered by the same guard.
Decoding in the webview click handler instead would work equally well; openFile() just happens
to be the single choke point.
Separately, it would help if showTextDocument failures surfaced a notification or an
output-channel line. The silent failure is what made this hard to diagnose, and it is the reason
the same defect has now been reported three times (#65548, #85641, this one) with three different
descriptions of the symptom.
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Still reproducible on extension 2.1.259 (darwin-arm64) — not stale.
I re-checked the shipped bundle today.
openFile()has changed since 2.1.233 (there is now a fallback lookup for relative paths that don't exist on disk), but it still never percent-decodes the incoming path:The new fallback doesn't help this case, because the search key is still the encoded string (
%E3%83%90%E3%83%83%E3%82%AF...), which matches no file on disk. So the original report and the suggested one-line guard inopenFile()both still apply exactly as written, and #85641 (%20/ paths containing spaces) is still covered by the same fix.Happy to send a PR for the fix if the source for
openFile()is somewhere I can reach — just point me at it.@graysenpack @grune-yamashita — you each reported this same defect from a different angle (#85641 via
%20in paths with spaces, #65548 via non-ASCII filenames). All three reports come down to one missing decode inopenFile(), and the one-line guard above fixes all of them.Right now the three reports split the signal three ways, which is likely why none of them has been picked up: this repo's sweep script (
scripts/sweep.ts) only exempts an issue from the stale/auto-close cycle if it has an assignee or 10+ 👍. #65548 was already auto-closed asnot plannedfor exactly that reason, and this one was labeledstalelast week.So if you're still hitting this, a 👍 on this issue — and a note here if your case differs from the trace above — would help keep it in front of triage rather than sweeping it again. Happy to consolidate everything here so there's a single thread to act on.
Still reproduces on 2.1.261 (darwin-arm64, published today). I read the shipped bundle: openFile() now has the absolute-path and relative-path fallbacks, but it still never percent-decodes, so a link to a path with a space fails exactly as it did on 2.1.259.
My case (#85641) is the same defect, just via %20. Consolidating everything here is fine with me.