Wrangler在WSL2里登录卡死:根因和验证过的解决办法

我在Windows 11 + WSL2 mirrored networking下遇到了Wrangler登录卡死的问题。查了一圈,最后发现问题居然出在运行Wrangler的Node.js runtime上。

环境

  • Windows 11
  • WSL2,使用mirrored networking
  • Wrangler 4.112.0
  • Volta 2.0.2
  • 通过Volta安装的pnpm 10.24.0
  • 升级后的shell默认版本:Node.js 26.5.0
  • pnpm exec wrangler实际使用的runtime:Node.js 24.11.1
  • Windows浏览器:Chrome
  • WSL里的HTTP_PROXYHTTPS_PROXY指向Clash Verge Rev的mixed port
  • Windows代理绕过localhost和intranet地址

现象

要登录wrangler,用了WRANGLER_LOG=debug pnpm exec wrangler login --callback-host=0.0.0.0 (0.0.0.0是因为https://github.com/cloudflare/workers-sdk/issues/13258)。 浏览器完成授权后,正常跳到了:

https://welcome.developers.workers.dev/wrangler-oauth-consent-granted

但Wrangler停在下面几条debug日志之后不动了:

fetching auth token grant_type=authorization_code
Checking if domain has Access enabled: dash.cloudflare.com
Access switch not cached for: dash.cloudflare.com
Caching access switch for: dash.cloudflare.com
Fetching auth token from https://dash.cloudflare.com/oauth2/token

关掉所有Chrome窗口也没能让Wrangler继续。

为什么不是callback连通性或者代理的问题

Wrangler 4.112.0会先用authorization code换取token,再把浏览器重定向到wrangler-oauth-consent-granted。所以浏览器能看到这个页面,至少说明:

  1. Windows里的浏览器可以访问WSL中的callback server。
  2. Wrangler验证了callback state和authorization code。
  3. Wrangler请求了token endpoint,并成功解析了响应。

接下来Wrangler会结束callback response,然后等待server.close(callback)。只有close callback得到执行,登录流程才会结束,Wrangler才会保存token。

为了避免反复在浏览器里点授权,我还单独验证了几条网络路径:

  • Undici 7.28.0通过同一个代理向Cloudflare token endpoint发POST请求,大约465 ms返回。
  • 自动注入一个无效的authorization code后,真正的Wrangler进程大约795 ms就返回了invalid_grant
  • 把token endpoint替换成本地mock并返回有效的OAuth响应,再从WSL里用curl访问callback,同一版Wrangler可以正常打印Successfully logged in.
  • Clash里没有localhost连接记录,符合Windows代理绕过localhost/intranet地址的设置。

Volta给出的误导性版本号

我先升级了默认Node版本:

volta install node@26

然后shell里显示:

$ node --version
v26.5.0

但是再试一次还是卡住。查看正在运行的进程,才发现Wrangler居然还跑在Node 24.11.1下面:

node ./node_modules/.bin/../wrangler/bin/wrangler.js login --callback-host=0.0.0.0
/home/<user>/.volta/tools/image/node/24.11.1/bin/node --no-warnings \
  .../wrangler/wrangler-dist/cli.js login --callback-host=0.0.0.0

下面两个命令暴露版本不一致的问题:

$ node --version
v26.5.0

$ pnpm exec node --version
v24.11.1

Volta安装的pnpm tool image仍然关联着Node 24.11.1。只看node --version,根本看不到Wrangler实际用的是哪个runtime。

Wrangler的debug telemetry里也记下了实际的major version:

"nodeVersion": 24

Socket证据

Wrangler卡住时,ss显示callback server上还留着一条连接:

ESTAB 0 0 127.0.0.1:8976 127.0.0.1:<ephemeral-port>

扩展TCP信息显示这条连接只收到了两个segment,之后几分钟都没有任何流量。这符合浏览器的speculative/pre-request TCP connection:Chrome先建立连接,但不发送HTTP请求。

Node.js的nodejs/node#63452描述了这个问题:Chrome可能创建一条不发送任何HTTP数据的speculative TCP connection,旧版Node.js在执行http.Server.close()时会一直等这条连接结束。

Node在nodejs/node#63470里修复了pre-request socket的处理,Node.js 26.4.0正式包含了这个修复。

验证过的解决办法

强制pnpm和Wrangler使用Node 26.5.0后,登录确实恢复正常:

WRANGLER_LOG=debug \
volta run --node 26.5.0 \
pnpm exec wrangler login --callback-host=0.0.0.0

登录前可以先用下面的命令确认实际runtime:

volta run --node 26.5.0 pnpm exec node --version

预期输出:

v26.5.0

通过volta run启动Wrangler后,浏览器完成授权,Wrangler正常打印了Successfully logged in.,没有继续卡住。

如果想永久更新pnpm关联的Node runtime,可以先选好新的默认Node版本,然后重新安装pnpm:

volta uninstall pnpm
volta install [email protected]
pnpm exec node --version

最后一个命令应该返回Node 26.5.0。

Wrangler可以改进的地方

上游Node修复已经解决了这个问题,但Wrangler还可以让排查和恢复简单一些:

  1. callback server关闭过程应该有超时,并在超时后报告还剩哪些socket。
  2. token exchange在成功跳转前就已经完成,也可以考虑在跳转成功后主动关闭callback连接。

声明:人类活动,但由Codex记录内容。


Last modified on 2026-07-19