[BUG] VS Code extension: chat file links fail silently for binary files and percent-encoded (non-ASCII/space) paths — root cause + fix
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:
[img](some-image.png)— any binary file (PNG/JPEG) in the workspace → nothing happens[план](plans/handoffs/Ф3-file.md)— any path with non-ASCII (Cyrillic, Japanese, …) or spaces → nothing happens[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.showErrorMessageas a defensive measure. - Related closed-as-stale issues: #37989, #69527, #65548.