microsoft / microsoft/TypeScript

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

未关闭
#63,885 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

Possible Improvement
主要语言
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.

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 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

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。