VSCode extension: chat file links with non-ASCII (CJK) or space-containing paths never open (webview percent-encodes href, host never decodes)

Open 💬 0 comments Opened Jul 10, 2026 by mintkoi233

Summary

In the VSCode extension's chat webview, markdown file links whose workspace-relative path contains non-ASCII characters (e.g. CJK) or spaces are dead: clicking them does nothing, with no error surfaced. The webview percent-encodes the href during markdown rendering, but the extension host never decodes it before resolving the path.

This affects any non-English workspace (Chinese/Japanese/Korean folder or file names, accented Latin, and also plain ASCII paths containing spaces).

Environment

  • Extension: anthropic.claude-code 2.1.206 (win32-x64) — also reproduced on 2.1.204
  • VSCode stable, Windows 11
  • Note: the extension's own system prompt instructs the model to emit workspace-relative markdown links ([filename.ts](src/filename.ts)), so the model produces exactly the links that break.

Repro

  1. In a workspace, create a file whose relative path contains CJK, e.g. 文件/報告.md.
  2. Have Claude output a markdown link in chat: [報告.md](文件/報告.md).
  3. Click the rendered link.
  4. Nothing opens. No toast/notification. (DevTools console of the extension host shows the path resolution attempt only.)

ASCII-only relative links (e.g. [PRD.md](PRD.md)) open fine.

Root cause (from reading the shipped bundles)

  1. webview/index.js — chat markdown is rendered with react-markdown. The remark/rehype pipeline's normalizeUri (micromark-util-sanitize-uri) percent-encodes non-ASCII characters in link destinations, so the anchor's href prop becomes %E6%96%87%E4%BB%B6/%E5%A0%B1%E5%91%8A.md.
  2. The custom anchor's onClick runs the href through a "looks like a file path" parser (regex ^([^:#]+?)(?:[:#]L?(\d+)(?:-L?(\d+))?)?$ plus extension/prefix heuristics). The encoded string still passes (ends with .md), and is sent to the host as open_file / filePath — still encoded.
  3. extension.js — the open_file handler resolves relative paths with path.join(workspaceFolders[0].uri.fsPath, filePath) and then vscode.workspace.fs.stat(...). There is no decodeURIComponent anywhere on this path (the only occurrences in extension.js belong to vendored libs — ajv, uri-js, axios). The literal %E6%96%87%E4%BB%B6 directory does not exist, stat throws ENOENT, and the failure is swallowed silently.

Two adjacent issues worth noting:

  • Absolute Windows paths can never open via chat links either: the file-link regex treats the drive-letter colon (c:\...) as a line-number separator, so the match fails and the click is ignored. So there is no absolute-path workaround.
  • Silent failure: when stat fails, nothing is surfaced to the user — a toast ("file not found: …") would have made this diagnosable without reading the bundle.

Suggested fix

Decode before resolving in the open_file handler, e.g.:

try { filePath = decodeURIComponent(filePath) } catch {}

(or decode in the webview before sendRequest({type:"open_file", ...})), plus optionally surface a notification when the resolved path does not exist.

Thanks! The extension is otherwise working great for CJK-heavy workspaces — this is the one place where non-ASCII paths consistently fall through.

View original on GitHub ↗