microsoft / microsoft/TypeScript
Bad tsserverPath in the unstable/sync API client surfaces as bare "EPIPE: broken pipe, write" instead of naming the executable
还没有人认领这个 Issue。
- 主要语言
- Go
- 星标
- 111k
- 派生
- 14.3k
- 平均合并
- 2 天 4 小时
- 30 天内合并 PR
- 132
描述
### 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.
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
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.
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- node.js, typescript
- 领域
- api, backend
- Issue 类型
- 缺陷
- 难度
- 3/5
- 预计耗时
- 1-2 天
- 活跃度
- 冷清
- 描述清晰度
- 描述清楚
- 新手友好度
- 70/100