Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Language server (tsc --lsp) exits with code 1 after `shutdown` and `exit`

未关闭 适合新手
#64,742 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
2/5
预计耗时
1-3 小时
新手友好度
76/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
go

调研方向

从tsc/internal/lsp/server.go开始,沿着 issue 中handleExit、dispatchLoop和Run的处理路径跟进;然后阅读tsc/cmd/tsc/lsp.go,错误会在那里变成退出码 1。使用提供的repro.py重现问题,分别测试打开文档和未打开文档的情况。完成标准是:正常的shutdown后接exit返回代码 0,同时 issue 所述的意外退出行为保持不变。

由索引模型根据 Issue 内容生成。

描述

🔎 Search Terms

tsc --lsp exit code 1, shutdown exit, context canceled, handleExit io.EOF, LSP exit notification

🕗 Version & Regression Information
  • I was unable to test this on prior versions because --lsp is new in TypeScript 7: seen with typescript 7.0.2 (tsc --lsp --stdio), macOS arm64. I have not run the nightly; the code path below is unchanged on main at aa81492.
⏯ Playground Link

No response (language server, not type checking)

💻 Code

Save as repro.py and run python3 repro.py in any directory. It initializes tsc --lsp --stdio, sends shutdown, then exit, and prints the exit code (given a URI, it opens a document first; no argument opens nothing).

# python3 repro.py [URI to open], in a directory with a tsconfig.json
import json, os, subprocess, sys

p = subprocess.Popen(["tsc", "--lsp", "--stdio"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)

def send(msg):
    body = json.dumps({"jsonrpc": "2.0", **msg}).encode()
    p.stdin.write(b"Content-Length: %d\r\n\r\n%s" % (len(body), body))
    p.stdin.flush()

def reply(id):
    while True:
        length = None
        while (line := p.stdout.readline()) not in (b"\r\n", b""):
            if line.lower().startswith(b"content-length:"):
                length = int(line.split(b":")[1])
        if length is None:
            return None  # the server is gone
        msg = json.loads(p.stdout.read(length))
        if "method" in msg and "id" in msg:  # a request from the server
            send({"id": msg["id"], "result": None})
        elif msg.get("id") == id:
            return msg

root = "file://" + os.getcwd()
send({"id": 1, "method": "initialize", "params": {"processId": os.getpid(), "rootUri": root, "capabilities": {}}})
reply(1)
send({"method": "initialized", "params": {}})
if len(sys.argv) > 1:
    doc = {"uri": sys.argv[1], "languageId": "typescript", "version": 0, "text": "const x = 1;\n"}
    send({"method": "textDocument/didOpen", "params": {"textDocument": doc}})
send({"id": 2, "method": "shutdown"})
if reply(2) is not None:
    send({"method": "exit"})
print("exit code:", p.wait())
🙁 Actual behavior
$ python3 repro.py
context canceled
exit code: 1

The server exits with code 1 after a clean shutdown and exit. Neovim reports any non-zero exit, so every :lsp restart shows "Client tsc quit with exit code 1 and signal 0. Check log for errors".

Reading main at aa81492, the path looks like this:

  • handleExit returns io.EOF.
  • dispatchLoop answers that with lspExit(nil), which cancels the loop's context.
  • Its next s.requestQueue.Get(ctx) then returns context.Canceled, and the loop returns that.
  • Run passes it on, since it isn't io.EOF and the group's context is done.
  • cmd/tsc/lsp.go prints it and returns 1.
🙂 Expected behavior

Exit code 0: the LSP spec asks for 0 when shutdown came before exit, and 1 otherwise.

Additional information about the issue

No response

主要语言
Go
星标
111k
派生
16.4k
平均合并
1 天 11 小时
30 天内合并 PR
148

环境准备

在 Codespaces 中打开

在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

microsoft/TypeScript 的其他 Issue

查看 microsoft/TypeScript 的全部 Issue

相似的 Issue

更多 Go Issue

把新 issue 发到你的邮箱

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