Help! VSCode tooling is broken for me on Windows

Hi! I use Windows with WSL in VSCode, and the editor tooling is behaving very oddly for me. I tested it out and from what I can tell I do not get these errors when developing directly on Windows without the wsl.

It seems to always be out of sync and is showing errors that don’t exist anymore, or it picks up on things that aren’t even errors. I’ve been restarting the dev server constantly, and instead of struggling I am hoping for some help.

Error I already fixed didn’t go away until I restarted ReScript.

This is always red.
image

Issues stay on screen and in the problems panel.

LSP server state

{
“lspServerVersion”: “1.72.0”,
“config”: {
“askToStartBuild”: true,
“logLevel”: “error”,
“inlayHints”: {
“enable”: false,
“maxLength”: 25
},
“codeLens”: false,
“binaryPath”: null,
“platformPath”: null,
“signatureHelp”: {
“enabled”: false,
“forConstructorPayloads”: false
},
“incrementalTypechecking”: {
“enable”: false,
“acrossFiles”: false,
“enabled”: true,
“debugLogging”: false
},
“cache”: {
“projectConfig”: {
“enable”: true
}
},
“runtimePath”: null,
“compileStatus”: {
“enable”: true
},
“allowBuiltInFormatter”: true,
“autoRunCodeAnalysis”: false
},
“projects”: [
{
“projectRootPath”: “/home/josh/Dev/rescript-lang.org”,
“openFiles”: [
“/home/josh/Dev/rescript-lang.org/src/bindings/ReactRouter.res”
],
“filesWithDiagnostics”: [
“file:///home/josh/Dev/rescript-lang.org/src/common/Hooks.res”
],
“filesDiagnostics”: {
“file:///home/josh/Dev/rescript-lang.org/src/common/Hooks.res”: [
{
“severity”: 2,
“tags”: [
1
],
“code”: 26,
“range”: {
“start”: {
“line”: 76,
“character”: 7
},
“end”: {
“line”: 76,
“character”: 7
}
},
“source”: “ReScript”,
“message”: “unused variable x.\nFix this by:\n- Deleting the variable if it’s not used anymore.\n- Prepending the variable name with _ (like _x) to ignore that the variable is unused.\n- Using the variable somewhere.”
}
]
},
“rescriptVersion”: “12.1.0”,
“bscBinaryLocation”: “/home/josh/Dev/rescript-lang.org/node_modules/rescript/node_modules/@rescript/linux-x64/bin/bsc.exe”,
“editorAnalysisLocation”: “/home/josh/Dev/rescript-lang.org/node_modules/rescript/node_modules/@rescript/linux-x64/bin/rescript-editor-analysis.exe”,
“namespaceName”: “”,
“hasPromptedToStartBuild”: true,
“bsbWatcherByEditor”: {
“pid”: 19326
}
}
],
“workspaceFolders”: [
“/home/josh/Dev/rescript-lang.org”
],
“runtimePathCache”: {
“/home/josh/Dev/rescript-lang.org”: “/home/josh/Dev/rescript-lang.org/node_modules/rescript/node_modules/@rescript/runtime”
}
}

Dump the LSP has an error:

Pos: 82:1

npm error could not determine executable to run
npm error A complete log of this run can be found in: /home/josh/.npm/_logs/2026-02-01T19_25_05_688Z-debug-0.log

Gemini seems to think the issue is related to the path globs defined in server.ts.

      const watchers = Array.from(workspaceFolders).flatMap(
        (projectRootPath) => [
          {
            // Only watch the root compiler log for each workspace folder.
            // In monorepos, `**/lib/bs/.compiler.log` matches every package and dependency,
            // causing a burst of events per save.
            globPattern: path.join(projectRootPath, c.compilerLogPartialPath),
            kind: p.WatchKind.Change | p.WatchKind.Create | p.WatchKind.Delete,
          },
          {
            globPattern: path.join(
              projectRootPath,
              "**",
              c.buildNinjaPartialPath,
            ),
            kind: p.WatchKind.Change | p.WatchKind.Create | p.WatchKind.Delete,
          },
          {
            globPattern: `${
              path.join(projectRootPath, "**", c.compilerDirPartialPath)
            }/**/*.{cmt,cmi}`,
            kind: p.WatchKind.Change | p.WatchKind.Delete,
          },
        ],
      );

The Problem
In a VS Code Remote environment (like WSL), absolute path globs are notoriously flaky.

  1. Path Mismatch: The Server (in WSL) generates a Linux path (/home/josh/...). The Client (on Windows) receives this request. While VS Code should handle this mapping, explicitly pinning watchers to absolute paths often fails when the file system and UI live on different OS kernels.
  2. Glob Syntax: VS Code watchers work best with Relative Patterns (e.g., **/src/*.res). When you use absolute paths containing ** (like /home/josh/project/**/lib...), strict file system watchers often reject them or fail to bind them to the correct workspace root logic.

This is what it suggests:

// FIX: Use relative glob patterns instead of absolute paths.
// This ensures compatibility with WSL/Remote environments where
// absolute paths often fail to map correctly between Client (Windows) and Server (Linux).
const watchers = [
  {
    // Watch for compiler log (triggers build status)
    // Using **/ ensures we catch it even if the path structure varies slightly,
    // and relies on VS Code's native exclusion (files.watcherExclude) to ignore node_modules.
    globPattern: `**/${c.compilerLogPartialPath}`,
    kind: p.WatchKind.Change | p.WatchKind.Create | p.WatchKind.Delete,
  },
  {
    // Watch for ninja build files
    globPattern: `**/${c.buildNinjaPartialPath}`,
    kind: p.WatchKind.Change | p.WatchKind.Create | p.WatchKind.Delete,
  },
  {
    // Watch for binary artifacts (.cmt/.cmi) to trigger diagnostics updates
    globPattern: `**/${c.compilerDirPartialPath}/**/*.{cmt,cmi}`,
    kind: p.WatchKind.Change | p.WatchKind.Delete,
  },
];

I tried testing it out locally, but I couldn’t get the local extension to run (perhaps another wsl issue…)

It might not actually work on windows. I tried checking out the rescript site repo on windows and I now have this error from the extension.

Node.js v22.21.1
[Info  - 6:40:53 PM] Connection to server got closed. Server will restart.
true
[Info  - 6:40:53 PM] Received initialize request from client.
node:internal/modules/esm/load:188
    throw new ERR_UNSUPPORTED_ESM_URL_SCHEME(parsed, schemes);
          ^

Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: Only URLs with a scheme in: file, data, node, and electron are supported by the default ESM loader. On Windows, absolute paths must be valid file:// URLs. Received protocol 'c:'
    at throwIfUnsupportedURLScheme (node:internal/modules/esm/load:188:11)
    at defaultLoad (node:internal/modules/esm/load:82:3)
    at ModuleLoader.load (node:internal/modules/esm/loader:815:12)
    at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:594:31)
    at #createModuleJob (node:internal/modules/esm/loader:624:36)
    at #getJobFromResolveResult (node:internal/modules/esm/loader:343:34)
    at ModuleLoader.getModuleJobForImport (node:internal/modules/esm/loader:311:41)
    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:664:25) {
  code: 'ERR_UNSUPPORTED_ESM_URL_SCHEME'
}

Node.js v22.21.1
[Error - 6:40:53 PM] The ReScript Language Server server crashed 5 times in the last 3 minutes. The server will not be restarted. See the output for more information.

Try add some getLogger().log statements, see rescript-vscode/server/src/incrementalCompilation.ts at 47d5dd34abf476368f3dcdef2b1b0818e81f2ec6 · rescript-lang/rescript-vscode · GitHub

That is how I troubleshoot these things on Windows, add logs and inspect the LSP Dump command (if you can).

This gets windows without WSL to work: fix: wrap binary path resolution with fileURLToPath by jderochervlk · Pull Request #1177 · rescript-lang/rescript-vscode · GitHub

With WSL I am seeing this logged out from the extension.

Did not find rewatch/rescript lockfile in project root, assuming bsb
Could not figure out call args. Maybe build.ninja does not exist yet?

It seems like another path issue.

1 Like

I think it’s somewhere in here.

    // projectRootPath is already normalized (NormalizedPath) from findProjectRootOfFile
    // Use getProjectFile to verify the project exists
    const project = utils.getProjectFile(projectRootPath);

If I log out project I get this:

{
    openFiles: Set(1) { '/home/josh/Dev/rescript-lang.org/src/Mdx.res' },
    filesWithDiagnostics: Set(0) {},
    filesDiagnostics: {},
    namespaceName: '',
    rescriptVersion: '12.0.0',
    bsbWatcherByEditor: null,
    buildRootPath: null,
    bscBinaryLocation: '/home/josh/Dev/rescript-lang.org/node_modules/@rescript/linux-x64/bin/bsc.exe',
    editorAnalysisLocation: '/home/josh/Dev/rescript-lang.org/node_modules/@rescript/linux-x64/bin/rescript-editor-analysis.exe',
    hasPromptedToStartBuild: true
  }

I don’t think buildRootPath should be null.

This is also interesting:

buildSystem: 'bsb',
buildRewatch: null,
buildNinja: null,

If it’s using bsb and not rewatch, could that be the reason why I have to restart the extension to pick up changes? There are also no incremental files being generated, but nothing changes if I disable incremental, it still doesn’t work.

Update 1

It’s something off with updating the intellisense, code lens, and inlay hints. It logs out the warnings and file as expected, it’s just not applying any updates. Restarting it does show everything correctly. I’m trying to find if there is a difference between first load and updates.

The dot completion does not work, but I can get autocomplete suggestions after typing in ->.