我在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_PROXY和HTTPS_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。所以浏览器能看到这个页面,至少说明:
- Windows里的浏览器可以访问WSL中的callback server。
- Wrangler验证了callback state和authorization code。
- 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还可以让排查和恢复简单一些:
- callback server关闭过程应该有超时,并在超时后报告还剩哪些socket。
- token exchange在成功跳转前就已经完成,也可以考虑在跳转成功后主动关闭callback连接。
声明:人类活动,但由Codex记录内容。
Last modified on 2026-07-19