[BUG] VS Code extension: chat file links fail silently for binary files and percent-encoded (non-ASCII/space) paths — root cause + fix

Open 💬 0 comments Opened Jul 11, 2026 by rybalkaie

Summary

In the VS Code extension, markdown file links in assistant responses ([name](path)) fail silently on click in two common cases. The cursor shows a pointer, but nothing opens — no editor tab, no error toast. Both bugs were reported before (#37989 for binaries, #69527 / #65548 for non-ASCII paths) and were closed as stale, but they are still present in v2.1.207. I traced both to their root cause in the shipped bundle; details + suggested fix below.

Environment

  • macOS (darwin arm64), VS Code 1.127.0
  • Extension: anthropic.claude-code 2.1.207 (latest as of 2026-07-11)

Repro

Ask Claude to output these links in chat, then click them:

  1. [img](some-image.png) — any binary file (PNG/JPEG) in the workspace → nothing happens
  2. [план](plans/handoffs/Ф3-file.md) — any path with non-ASCII (Cyrillic, Japanese, …) or spaces → nothing happens
  3. [test](src/file.ts) — plain ASCII text file → works fine

Root cause (from the shipped bundle, v2.1.207)

Bug 1 — binary files. openFile() in extension.js opens everything via vscode.window.showTextDocument(uri). For binary files the promise rejects with cannot open file:///…/file.png. Detail: File seems to be binary and cannot be opened as text (visible in the renderer log). The rejection is unhandled, so the user sees nothing.

Bug 2 — non-ASCII / spaces. The chat webview renders markdown with react-markdown; mdast-util-to-hast runs the link destination through micromark's normalizeUri, which percent-encodes every non-ASCII char and spaces (Ф3.md%D0%A43.md). The webview's file-link matcher accepts the encoded href and sends it as open_file.filePath verbatim. On the extension-host side openFile() never calls decodeURIComponent, so fs.existsSync fails, the fuzzy-search fallback finds nothing, and showTextDocument rejects on a nonexistent path — again silently.

Suggested fix

In openFile(filePath, location):

try { filePath = decodeURIComponent(filePath) } catch {}
// ...
vscode.window.showTextDocument(uri).then(
  editor => { /* existing reveal/selection logic */ },
  () => vscode.commands.executeCommand('vscode.open', uri) // binary → image preview etc.
)

I patched exactly this into my local extension.js and all four cases (relative, absolute, Cyrillic, PNG, file outside the workspace root) now open correctly, with line-number locations still working. Would be great to have this upstream so the patch doesn't have to be reapplied after every extension update.

Notes

  • Since the failure is silent, consider surfacing open errors via vscode.window.showErrorMessage as a defensive measure.
  • Related closed-as-stale issues: #37989, #69527, #65548.

View original on GitHub ↗