microsoft / microsoft/TypeScript

Bad tsserverPath in the unstable/sync API client surfaces as bare "EPIPE: broken pipe, write" instead of naming the executable

Offen
#63,885 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Possible Improvement
Vorherrschende Sprache
Go
Sterne
111k
Forks
14.3k
Ø Merge
2 T. 4 Std.
Gemergte PRs (30 T.)
132

Beschreibung

### Version

- `typescript@7.0.2` (`gitHead` `2bd066d87f5bafd315be9f40889d0a60b9e58e0b`),
`@typescript/typescript-linux-x64@7.0.2`
- Node v22.22.0, Linux x86_64 (Fedora 43)

### Repro

```js
import { API } from "typescript/unstable/sync";

const api = new API({ tsserverPath: "/nonexistent/binary" });
api.parseConfigFile("/some/tsconfig.json");
```

### Expected

An error identifying the executable, along the lines of the default path's
`Executable not found: `, or the channel's own
`Unexpected EOF while reading from child process (exited with code N)`.

### Actual

```
Error: EPIPE: broken pipe, write
at writeSync (node:fs:922:3)
at SyncRpcChannel.writeAllBuf (.../dist/api/syncChannel.js:495:27)
at SyncRpcChannel.writeTuple (.../dist/api/syncChannel.js:314:18)
at SyncRpcChannel.requestBytesSync (.../dist/api/syncChannel.js:221:14)
at Client.apiRequest (.../dist/api/sync/client.js:58:37)
```

The same `EPIPE` appears for any `tsserverPath` that is not an API server —
`/bin/cat` and `/bin/sleep` both produce it — so the message never distinguishes
"executable missing" from "executable is not a tsgo API server".

### Analysis

- `resolveExePath` (`dist/api/options.js`) returns `options.tsserverPath`
unchecked: `return options.tsserverPath ?? getExePath();`. The default branch,
`getExePath` (`lib/getExePath.js`), does `fs.existsSync(exe)` and throws
`Executable not found: ` — the explicit-path branch has no such check.
- `SyncRpcChannel.writeAllBuf` (`dist/api/syncChannel.js`) catches only
`EAGAIN`/`EWOULDBLOCK` and rethrows everything else raw. The read side has an
`eofError()` helper that reports the child's `exitCode`/`signalCode`; the write
side has no equivalent, so a child that died before the first request produces
the low-level errno instead.
- The `spawn` `"error"` event (`ENOENT`) is never observed on the child.

A check in `resolveExePath` mirroring `getExePath`'s `existsSync`, plus an
`EPIPE` branch in `writeAllBuf` that raises the channel's `eofError()`, would
cover both shapes.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Start with resolveExePath in dist/api/options.js and compare it with getExePath in lib/getExePath.js, then inspect SyncRpcChannel.writeAllBuf and eofError in dist/api/syncChannel.js. Re-run the supplied sync API example with /nonexistent/binary and a non-server executable; done means failures identify the executable or child-process exit instead of exposing a bare EPIPE.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
node.js, typescript
Bereich
api, backend
Issue-Typ
Bug
Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Aktivitätsstatus
Ruhig
Klarheit
Klar beschrieben
Anfängerfreundlichkeit
70/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.