[VSCode Extension] Markdown links to files with non-ASCII (e.g. Japanese) filenames fail silently to open
Summary
In the VSCode extension (v2.1.161), clicking a markdown link in the chat that points to a file with non-ASCII characters in its path (e.g. Japanese, Chinese, Korean filenames) does nothing. The click is intercepted but the file is not opened in the editor.
ASCII-only paths work correctly.
Environment
- Extension:
anthropic.claude-codev2.1.161 (darwin-arm64) - VSCode: latest
- OS: macOS 14 (Darwin 24.6.0)
- Repro file path:
/path/to/workspace/some_dir/20260520_千葉様ヒアリング_議事録.md
Reproduction
- Have a workspace file with non-ASCII characters in the filename (e.g.
議事録.md) - In Claude Code chat, the assistant outputs a markdown link:
[議事録](some_dir/議事録.md) - Click the link
Expected: File opens in the editor (same as ASCII-named files).
Actual: Nothing happens. No error message, no editor open.
Right-clicking the link → "Copy Link" returns the percent-encoded path (some_dir/%E8%AD%B0%E4%BA%8B%E9%8C%B2.md), which confirms encoding is happening in the rendering pipeline.
Root Cause
Traced through extension.js and webview/index.js (v2.1.161):
- The markdown parser (micromark/remark) percent-encodes non-ASCII URL characters per CommonMark spec → React component receives
href="%E8%AD%B0...%E9%8C%B2.md". - The webview click handler (
ox()regex parser) accepts the encoded string as a valid file path (it ends in.md) and passes it tofileOpener.open(). - The RPC sends
{type: "open_file", filePath: "%E8...%E9%8C%B2.md"}to the extension. - In
extension.js, theopenFile(z, V)handler does:
``js/cwd/some_dir/%E8...%E9%8C%B2.md
let N = path.isAbsolute(z) ? z : path.join(this.cwd, z);
// N is now which does NOT exist on disk/cwd/some_dir/議事録.md
// The actual file is ``
fs.existsSync(N)returns false. ThefindFilesfallback also fails because it searches with the encoded glob, not the decoded name.fs.statSync(N)insidetry{...}catch{}throws (file missing); the catch swallows it.vscode.window.showTextDocument(Uri.file(N))is called with the non-existent path → silently fails (no toast, no log).
Suggested Fix
In openFile(z, V), decode the incoming path before resolving:
openFile(z, V) {
let decoded;
try { decoded = decodeURIComponent(z); } catch { decoded = z; }
let N = path.isAbsolute(decoded) ? decoded : path.join(this.cwd, decoded);
// ... rest unchanged
}
Alternatively, decode in the webview before sending the RPC.
Tested Variants (all NG in v2.1.161)
| # | Format | Result |
|---|--------|--------|
| 1 | [t](dir/議事録.md) (raw Japanese, relative) | ❌ |
| 2 | [t](dir/%E8%AD%B0%E4%BA%8B%E9%8C%B2.md) (pre-encoded) | ❌ |
| 3 | [t](./dir/議事録.md) (with ./) | ❌ |
| 4 | [t](<dir/議事録.md>) (angle brackets) | ❌ |
| 5 | [t](/abs/path/議事録.md) (absolute) | ❌ |
| 6 | [t](file:///abs/path/議事録.md) | ❌ |
| 7 | [t](議事録.md) (filename only, findFiles fallback) | ❌ |
Impact
Non-ASCII filenames are common for users working in Japanese / Chinese / Korean / Cyrillic etc. The assistant's instruction to "use markdown link syntax to make files clickable" silently fails for these users.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗