[VSCode Extension] Markdown links to files with non-ASCII (e.g. Japanese) filenames fail silently to open

Resolved 💬 1 comment Opened Jun 5, 2026 by grune-yamashita Closed Jul 11, 2026

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-code v2.1.161 (darwin-arm64)
  • VSCode: latest
  • OS: macOS 14 (Darwin 24.6.0)
  • Repro file path: /path/to/workspace/some_dir/20260520_千葉様ヒアリング_議事録.md

Reproduction

  1. Have a workspace file with non-ASCII characters in the filename (e.g. 議事録.md)
  2. In Claude Code chat, the assistant outputs a markdown link: [議事録](some_dir/議事録.md)
  3. 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):

  1. 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".
  2. The webview click handler (ox() regex parser) accepts the encoded string as a valid file path (it ends in .md) and passes it to fileOpener.open().
  3. The RPC sends {type: "open_file", filePath: "%E8...%E9%8C%B2.md"} to the extension.
  4. In extension.js, the openFile(z, V) handler does:

``js
let N = path.isAbsolute(z) ? z : path.join(this.cwd, z);
// N is now
/cwd/some_dir/%E8...%E9%8C%B2.md which does NOT exist on disk
// The actual file is
/cwd/some_dir/議事録.md
``

  1. fs.existsSync(N) returns false. The findFiles fallback also fails because it searches with the encoded glob, not the decoded name.
  2. fs.statSync(N) inside try{...}catch{} throws (file missing); the catch swallows it.
  3. 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.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗