[BUG] VS Code extension: chat file links are never wired to the existing open_file bridge
Preflight Checklist
- [x] I have searched existing issues — this behaviour has been reported before (#10846, #16056, #44713, #51015, #57100, #72889), but every one of those is closed and locked, and none of them identifies the cause. The closing bot asks to file a new issue, so here it is, with the root cause.
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
Markdown file links rendered in the chat panel of the VS Code extension are styled as links but clicking them does nothing — no open, no reveal, no error. This is an affordance mismatch, and it hits exactly at handoff time, when Claude has just produced a deliverable.
The extension's own system prompt (## Code References in Text) instructs Claude to emit file references in precisely this markdown format. The links are dead on arrival.
I dug into the installed bundle. There are two independent defects, and neither is "link handling is missing".
1 — the anchors are never wired to the bridge that already exists.
The open path is present, complete, and in active use by the file chips and the diff view:
webview/index.js openFile(filePath, location)
-> sendRequest({type: "request", requestId, request: {type: "open_file", filePath, location}})
extension.js case "open_file": -> this.openFile(request.filePath, request.location)
The host side is thorough: it resolves relative paths against cwd, has fallbacks when the file is missing, and calls revealInExplorer for directories. Nothing about it is broken. The rendered <a> elements simply never call it.
2 — binary files fail silently even once (1) is fixed.
The host's openFile ends in
vscode.window.showTextDocument(uri).then(cb) // no rejection handler
showTextDocument rejects for non-text files. With no onRejected and no .catch, the rejection is unhandled and the user sees nothing at all. So a link to a .png or .pdf stays dead even after the anchors are wired up.
What Should Happen?
Clicking a file link should open the file — text in the editor, binary in its own viewer (image preview, PDF) — and a directory should reveal in the Explorer. Line anchors (file.md#L42, #L42-L51) should map to the location argument the host already accepts.
Error Messages/Logs
None. The click is a silent no-op. Defect 2 produces an unhandled promise rejection from showTextDocument inside the extension host; nothing surfaces to the user.
Steps to Reproduce
- Ask Claude to create two files in a subfolder, e.g.
docs/note.mdanddocs/chart.png. - Claude replies with
[note.md](docs/note.md)and[chart.png](docs/chart.png)— the format its system prompt mandates. - Click either link in the chat panel. Nothing happens.
- Same result with absolute paths,
file:///URLs and directory paths (previously reported in #51015).
Claude Model
Opus 5
Is this a regression?
Yes, and a recurring one. #10846 was reported fixed in v2.1.4; broken again by v2.1.92 (#44713); again in 2.1.132 (#57100); still broken in 2.1.263.
Last Working Version
2.1.4 (per #10846)
Claude Code Version
Extension anthropic.claude-code-2.1.263-linux-x64, VS Code 1.132.0
Platform
VS Code extension (chat panel webview)
Operating System
Debian 13 (trixie), KDE Plasma on X11
Terminal/Shell
zsh — not relevant here; the defect is in the webview panel, not the CLI.
Additional Information
The desktop side is not at fault. Verified locally before filing: VS Code installed from the native .deb (no Flatpak/Snap sandbox), xdg-open present, three xdg-desktop-portal processes running, an image handler registered for image/png. None of that is ever reached.
Suggested fix — both parts are small:
- Webview: on click of an anchor whose
hrefcarries no URL scheme and is not a#fragment, parse an optional#L<n>/#L<n>-L<m>suffix intolocationand call the existingopenFile(). External schemes keep their current behaviour. - Host: give
showTextDocument(uri).then(cb)a rejection handler that falls back tovscode.commands.executeCommand("vscode.open", uri). One argument.
Workaround while this is open: a patch script that applies both fixes to the locally installed extension — idempotent, backs up per version, verifies with node --check and rolls back automatically on a syntax error, --revert to undo. It contains no Anthropic code; it locates the insertion points by pattern. → https://github.com/0nelight/claude-code-vscode-linkfix
Happy to open a PR against the extension source if that is ever practical.