VS Code extension: clicking chat links to binary files (images) silently fails — unhandled showTextDocument rejection
Summary
In the VS Code extension's chat panel, clicking a markdown link to any binary file (PNG, JPG, PDF, …) silently does nothing. The extension resolves the path correctly, then tries to open it with vscode.window.showTextDocument(), which rejects binary files — and the rejection is unhandled, so the user gets no error, no feedback, nothing.
For image-heavy workflows (e.g. Claude generating/reviewing art assets and linking them for review) this makes every link the model emits dead, and the user has to copy paths by hand and navigate manually.
Environment
- Claude Code VS Code extension: reproduced on every version I inspected from 2.1.123 (April) through 2.1.220 (current) — the code path is unchanged
- IDE: Antigravity (VS Code fork), macOS 15 / Darwin 25.5.0 — but the bug is in the extension's own handler and should reproduce in stock VS Code (
showTextDocumentrejects binaries everywhere)
Repro
- Have Claude output a relative markdown link to any PNG in the workspace, e.g.
[shot.png](assets/shot.png) - Click it in the chat panel
- Nothing happens. The extension host log shows:
[error] CodeExpectedError: cannot open file:///Users/me/project/assets/shot.png.
Detail: File seems to be binary and cannot be opened as text
Links to text files (.md, .ts, …) work fine.
Root cause
In extension.js, the webview's open_file request is handled by openFile(filePath, location), which — after correct path resolution and a directory check that goes to revealInExplorer — unconditionally does:
ue.window.showTextDocument(n).then((i) => { /* selection/reveal logic */ })
showTextDocumentrejects withCodeExpectedErrorfor binary files- the promise has no rejection handler, so the failure is swallowed silently
No link-format workaround exists from the model side: file:// hrefs survive the markdown sanitizer but the webview host drops them, and custom-scheme deep links (vscode://file/... / fork equivalents) are stripped by the sanitizer's allowedSchemes list.
Suggested fix
Route non-text files through the generic opener, e.g.:
vscode.commands.executeCommand('vscode.open', uri)
either by sniffing known binary extensions before showTextDocument, or as a .catch() fallback when showTextDocument rejects (which also future-proofs any other non-text-openable resource). vscode.open shows images in the built-in image preview, which is presumably the expected UX.
At minimum, surfacing the rejection as an error notification would stop the failure from being silent.
Current workaround
Locally patching the installed extension.js to insert the extension-sniff + vscode.open fallback before the showTextDocument call fixes clicking for images — but the patch is wiped by every extension auto-update (which currently ship every 1–2 days), hence this report.
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Independently confirmed, including the suggested fix.
.pngdoes nothing;.mdlinks in the same folder open fine.extension.js— wrapping theopenFilehandler'sshowTextDocument(uri).then(...)with a rejection handler that falls back tovscode.commands.executeCommand("vscode.open", uri)— and image links immediately open in the built-in image preview in both editors. No side effects observed for text files, directories (revealInExplorerpath untouched), or line-range selection links.Can confirm the workaround pain too: the local patch is wiped by every extension auto-update, so we're re-applying it from a script. A
.catch()fallback tovscode.openupstream would make this whole class of failure (any resourceshowTextDocumentcan't open) non-silent and correct.Confirming this on 2.1.219 (stock VS Code, macOS), plus one detail that may matter for triage: it is not limited to the markdown links Claude writes in prose. The webview routes several different affordances through the same
open_filerequest, and therefore through the sameopenFile()handler:Read screenshot.pngrow (theReadtool renderer callsopener.open(file_path, …)from itsheader())@-mention chipsAll of them are equally dead for images, for the reason described above. That makes the blast radius wider than "links in an answer": having Claude read a screenshot and then clicking its name in the tool row is probably the most common way a user runs into this.
Worth noting because that tool-row variant was already filed separately as #37989 and closed as stale, and #76679 covers the same handler from yet another angle. Since all these call sites converge on that one function, a
.catch()fallback tovscode.openinopenFile()fixes every one of them at once.Still reproducible on the current extension (2.1.260-win32-x64) in stock VS Code 1.136.1 on Windows 10 — same code path.
Confirms @wuesten-fuchs' point: the
Read <file>.pngtool-row header link hits the sameopenFilehandler, so screenshots Claude reads for verification cannot be opened from the transcript at all (text files andEditrows open fine).Local workaround I'm running (in
openFile, right after the directory check):vscode.openroutes through the built-in image preview / custom editors, so it also fixes #81482 (PDF). A more general fix is to.catch()theshowTextDocumentrejection and fall back tovscode.open.