opencode icon indicating copy to clipboard operation
opencode copied to clipboard

fix: Windows LSP URIs using backslashes (Biome initialization failure)

Open alopez-inf opened this issue 1 month ago • 3 comments

Summary

On Windows, the LSP client is currently sending URIs built from Windows paths with backslashes (\). This results in invalid file:// URIs and causes strict LSP servers like Biome to fail during initialize with a URI parsing error (e.g. “unexpected character at index 9”).

LSP requires URIs conforming to RFC 3986, which uses / as the path separator even on Windows (e.g. file:///c:/project/file.ts).

Evidence

{
  "$schema": "https://opencode.ai/config.json",
  "lsp": {
    "typescript":{
      "disabled": true
    },
    "biome": {
      "command": [
        "bunx",
        "@biomejs/biome@latest",
        "lsp-proxy",
        "--stdio"
      ],
      "extensions": [
        ".js",
        ".mjs",
        ".cjs",
        ".jsx",
        ".ts",
        ".mts",
        ".cts",
        ".tsx",
        ".d.ts",
        ".d.mts",
        ".d.cts",
        ".json",
        ".jsonc",
        ".css",
        ".html",
        ".htm",
        ".graphql",
        ".gql",
        ".vue",
        ".svelte",
        ".astro"
      ]
    }
  }
}

Example log when opening a file on Windows:

INFO  2025-12-10T09:55:29 +17ms service=lsp file=.\web\provaH.html touching file
INFO  2025-12-10T09:55:29 +143ms service=lsp serverID=biome spawned lsp server
INFO  2025-12-10T09:55:29 +1ms service=lsp.client serverID=biome starting client
INFO  2025-12-10T09:55:29 +3ms service=lsp.client serverID=biome sending initialize
ERROR 2025-12-10T09:55:30 +1113ms service=lsp.client serverID=biome error=unexpected character at index 9 initialize error
ERROR 2025-12-10T09:55:30 +0ms service=lsp error=LSPInitializeError Caused by: unexpected character at index 9 Failed to initialize LSP client biome
INFO  2025-12-10T09:55:30 +1ms service=default directory=C:\Users\alopez\Desktop\repos\infordisa-portal-nat disposing instance

This matches what you’d expect if the LSP server receives a URI like:

file:///C:\Users\...

instead of:

file:///c:/Users/...

Current Fix

I’ve implemented a change so that, when building URIs from filesystem paths, we now use:

import { pathToFileURL } from "url";

const uri = pathToFileURL(item).href;

This is done to let Node handle the file:// URI normalization (including converting backslashes to forward slashes and properly encoding the path).

On Windows, this fixes the issue in my tests: Biome now initializes correctly and works as expected.

Fix Evidence

INFO  2025-12-10T11:07:15 +1ms service=lsp.client serverID=biome starting client
INFO  2025-12-10T11:07:15 +4ms service=lsp.client serverID=biome sending initialize
INFO  2025-12-10T11:07:15 +9ms service=vcs branch=fix/windows-uri-fix-lsp initialized
INFO  2025-12-10T11:07:15 +0ms service=bus type=file.watcher.updated subscribing
INFO  2025-12-10T11:07:16 +1293ms service=lsp.client serverID=biome initialized
INFO  2025-12-10T11:07:16 +0ms service=bus type=lsp.updated publishing
INFO  2025-12-10T11:07:16 +1ms service=lsp.client serverID=biome path=C:\Users\alopez\Desktop\repos\infordisa-portal-nat\web\provaH.html waiting for diagnostics
INFO  2025-12-10T11:07:16 +0ms service=bus type=lsp.client.diagnostics subscribing
INFO  2025-12-10T11:07:16 +2ms service=lsp.client serverID=biome path=C:\Users\alopez\Desktop\repos\infordisa-portal-nat\web\provaH.html textDocument/didOpen
INFO  2025-12-10T11:07:19 +3007ms service=bus type=lsp.client.diagnostics unsubscribing
{}
INFO  2025-12-10T11:07:19 +1ms service=default directory=C:\Users\alopez\Desktop\repos\opencode\packages\opencode disposing instance
INFO  2025-12-10T11:07:19 +0ms service=state key=C:\Users\alopez\Desktop\repos\opencode\packages\opencode waiting for state disposal to complete
INFO  2025-12-10T11:07:19 +2ms service=lsp.client serverID=biome shutting down
INFO  2025-12-10T11:07:19 +2ms service=lsp.client serverID=biome shutdown

Disclaimer / Request for Review

I’m not very experienced with URI edge cases (UNC paths, non-ASCII, already-encoded paths, etc.), so while pathToFileURL(item).href looks like the correct and simplest solution, I’m not 100% sure there are no side effects on other platforms or setups. Feel free to offer improvements, comments, or whatever. And do some extra testing before merging this.

alopez-inf avatar Dec 10 '25 11:12 alopez-inf

/review

rekram1-node avatar Dec 10 '25 16:12 rekram1-node

lgtm

github-actions[bot] avatar Dec 10 '25 16:12 github-actions[bot]

If anything else is needed tell me

alopez-inf avatar Dec 11 '25 09:12 alopez-inf