Repository navigation
Description
Problem
When no runnable typescript-language-server is found (neither the project-local one nor one on PATH), TypescriptServer.spawn falls back to bunx inside a try/catch (packages/lsp/src/server/typescript.ts:319-330):
try {
const proc = spawn('bunx', [`typescript-language-server@${TS_LANGUAGE_SERVER_VERSION}`, '--stdio'], { … })
attachLSPProcessHandlers(proc, 'typescript')
return { process: proc }
}
catch (err) {
log.error({ err }, 'Failed to spawn typescript-language-server via bunx')
return undefined
}spawn from node:child_process does not throw when the command is missing. It returns a child process and later emits an async error event (ENOENT). This was confirmed under both Bun and Node while working on #134. So when bunx is not on PATH, the catch never runs:
spawnreturns a handle to a process that never started, rather thanundefined.LSPManager.schedule(packages/lsp/src/index.ts) marks a server broken only whenspawnreturnsundefinedor throws. It treats this dead handle as live and waits out the initialize timeout before giving up.- The only log line is the generic
LSP process errorfromattachLSPProcessHandlers. TheFailed to spawn … via bunxmessage never appears.
Expected
Check for bunx before spawning, as BiomeServer does since #134 (packages/lsp/src/server/biome.ts:77-89):
const bunx = Bun.which('bunx', { PATH: process.env.PATH ?? '' })
if (!bunx) {
log.warn({ root }, '<install hint>')
return undefined
}
const proc = spawn(bunx, [`typescript-language-server@${TS_LANGUAGE_SERVER_VERSION}`, '--stdio'], { … })- Return
undefinedwhen bunx is missing, so the server is marked broken right away instead of waiting out the initialize timeout. - Pass the explicit
PATHtoBun.which. Bun otherwise reads the copy ofPATHit captured at startup, and the tests changePATHat runtime. - Spawn the resolved absolute path, not the bare
bunxname. That is what cleared SonarCloud S4036 on fix(lsp): run a pinned @biomejs/biome in the biome bunx fallback #134. - Drop the dead
try/catch.
Tests
Add a case to the existing TypescriptServer classic-fallback tests in packages/lsp/test/unit/server.test.ts, modeled on the "returns undefined with the install hint when bunx is missing" test from #134. Set PATH to an empty temp dir, then assert that spawn returns undefined and that log.warn was called with the hint. The test should fail when the pre-check is removed.
Notes
PyrightServer(packages/lsp/src/server/pyright.ts:21-32) has the same deadtry/catcharoundspawn('bunx', ['pyright-langserver', '--stdio']). It could get the same fix in this change or in a separate issue. Its bunx call is also unpinned, and it callsBun.which('pyright-langserver')without the explicitPATH.
Activity