VSCode 连接 SSH 时 getcwd 报错的解决方法

TL;DR:服务器的 File System(FS)可能出现了异常,导致 SSH 会话继承的 Current Working Directory(CWD)失效,VSCode Server 因为无法执行 getcwd() 而退出。在本机的 SSH 配置中使用 RemoteCommand cd /tmp && exec /bin/bash,让 VSCode Server 从有效目录启动,即可绕过这一问题。

问题描述

我在使用本机的 VSCode 通过 Remote - SSH 连接服务器时,始终无法建立远程连接。但是,直接在终端中使用 ssh 可以正常登录服务器,密码认证也已经成功。即便 SSH 登陆成功,在执行各种命令的时候终端仍会报错:

bash
1sudo apt install zsh
apt 指令报错
apt 指令报错

从日志来看,VSCode Server 已经完成安装、启动并监听端口:

text
1Authenticated to a.b.c.d ([a.b.c.d]:6988) using "password".
2Remote server is listening on port 34311
3Server started

真正的问题出现在 VSCode Server 读取当前工作目录时:

text
1shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
2sh: 0: getcwd() failed: No such file or directory
3Error: ENOENT: process.cwd failed with error no such file or directory, uv_cwd
VSCode Remote - SSH 完整日志(已脱敏,节选)
text
 1[14:45:19.952] stderr> Authenticated to <HOST> ([<HOST>]:<PORT>) using "password".
 2[14:45:20.047] stderr> client_global_hostkeys_prove_confirm: server gave bad signature for RSA key 0: incorrect signature
 3
 4...
 5
 6[14:45:20.050] stderr> shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
 7[14:45:20.130] stderr> job-working-directory: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
 8[14:45:20.171] > /bin/bash
 9[14:45:20.171] Parent Shell: bash
10
11...
12
13[14:45:20.261] > Found existing installation at <REMOTE_HOME>/.vscode-server...
14> Starting VS Code CLI...
15[14:45:20.269] > Spawned remote CLI
16> Waiting for server log...
17
18...
19
20[14:45:20.306] Remote server is listening on port <REMOTE_PORT>
21
22...
23
24[14:45:20.478] [server] Checking <REMOTE_HOME>/.vscode-server/... for a running server...
25[14:45:20.478] [server] Installing and setting up Visual Studio Code Server...
26[14:45:20.479] [server] Server setup complete
27[14:45:20.482] [server] Starting server...
28
29...
30
31[14:45:20.489] [server] sh: 0: getcwd() failed: No such file or directory
32[14:45:20.568] [server] Error: ENOENT: process.cwd failed with error no such file or directory, the current working directory was likely removed without changing the working directory, uv_cwd
33
34...
35
36[14:45:20.573] [server] {
37[14:45:20.573] [server]   errno: -2,
38[14:45:20.573] [server]   code: 'ENOENT',
39[14:45:20.574] [server]   syscall: 'uv_cwd'
40[14:45:20.574] [server] }
41
42...
43
44[14:45:20.616] SSH Resolver called for "ssh-remote+<HOST>", attempt 3, (Reconnection)
45
46...
47
48[14:45:20.619] Running server is stale. Ignoring

另外,观察到在服务器的 VNC 界面中,

bash
1cd ~
2code .

会启动失败,报错信息如下:

text
 1Error: ENOENT: process.cwd failed with error no such file or directory, the current working directory was likely removed without changing the working directory, uv_cwd
 2    at process.wrappedCwd [as cwd] (node:internal/bootstrap/switches/does_own_process_state:142:28)
 3    at Gs (file:///usr/share/code/resources/app/out/cli.js:433:75892)
 4    at file:///usr/share/code/resources/app/out/cli.js:433:75997
 5    at ModuleJob.run (node:internal/modules/esm/module_job:439:25)
 6    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:633:26)
 7    at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:116:5) {
 8  errno: -2,
 9  code: 'ENOENT',
10  syscall: 'uv_cwd'
11}
打开 VSCode 失败
打开 VSCode 失败

bash
1cd ~/Desktop
2code ~

或者:

bash
1cd /tmp
2code ~

就没有问题。

成功打开 VSCode
成功打开 VSCode

原因分析

getcwd() 用来获取进程的当前工作目录。正常情况下,即使目录为空,它也不应该报错。结合这台服务器上的其他现象,我更倾向于认为根本原因是服务器的 FS 出现了异常,CWD 失效只是它直接表现出来的结果。

bash
1cd ~/Desktop
2code ~

或者:

bash
1cd /tmp
2code ~

这里的 ~ 是传给 code 的参数,表示需要打开的目录;~/Desktop/tmp 才是 VSCode 进程启动时继承的 CWD。打开的目录仍然是 ~,但从有效的 CWD 启动后,VSCode 就能正常运行。因此,VSCode 的安装和用户主目录本身都没有问题。

一种可能的情况是:用户目录或它上层的挂载点被重新创建、替换或重新挂载后,SSH 网关、远程容器或者 VNC 服务的父进程仍然持有旧目录。子进程继续继承这个已经无法在当前 FS 中解析的目录,于是 getcwd() 返回 ENOENT

这也解释了为什么普通 SSH 看起来仍然可以使用。Shell 中的 $PWD 只是一个环境变量,终端提示符即使仍然显示 ~,也不代表内核中的 CWD 可以被正确解析。一些不依赖 CWD 的命令可以继续执行(比如 lscdpwd),但 Node.js 启动 VSCode Server 时会调用 process.cwd(),因此直接退出。

解决方案

修改 SSH 配置

在本机的 ~/.ssh/config 中增加一个专门供 VSCode 使用的 Host:

sshconfig
1Host alias-of-the-server
2  HostName a.b.c.d
3  User xxx
4  Port yyyy
5  RemoteCommand cd /tmp && exec /bin/bash

重点在于:

sshconfig
1RemoteCommand cd /tmp && exec /bin/bash

SSH 连接建立后,它会先切换到一定存在的 /tmp,然后启动 Bash。VSCode 随后发送到远端的安装和启动脚本都会由这个 Bash 执行,因此 VSCode Server 会继承 /tmp 作为有效的 CWD。

之所以使用一个新的 Host,而不是直接修改原来的配置,是因为 RemoteCommand 会影响该 Host 下的所有 SSH 连接。创建一个专用别名,可以避免影响普通的交互式 SSH。

使用下面的命令验证配置:

bash
1printf 'pwd\nexit\n' | ssh -T alias-of-the-server

如果最后输出 /tmp,就说明后续命令已经从有效目录启动。

修改 VSCode 设置

在 VSCode 中打开 Preferences: Open User Settings (JSON),加入:

json
1{
2  "remote.SSH.useLocalServer": true,
3  "remote.SSH.enableRemoteCommand": true,
4  "remote.SSH.useExecServer": false
5}

总结

这个问题的直接原因是 VSCode Server 继承了失效的 CWD,深层原因则更可能是服务器 FS 或挂载状态异常。RemoteCommand 并没有修复 FS,而是在启动 VSCode Server 前先切换到 /tmp,绕开了失效目录。