openclaw - ✅(Solved) Fix @tencent-weixin/openclaw-weixin login fails with TypeError: fetch failed inside Gateway process [1 pull requests, 8 comments, 8 participants]

Official PRs (…)
ON THIS PAGE

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#78434Fetched 2026-05-07 03:36:56
View on GitHub
Comments
8
Participants
8
Timeline
12
Reactions
3
Timeline (top)
commented ×8cross-referenced ×3closed ×1

Error Message

Failed to start login: TypeError: fetch failed Channel login failed: Error: Failed to start login: TypeError: fetch failed

Fix Action

Workaround

None found. Uninstalled the plugin to avoid error log noise from auto-restart loop.

PR fix notes

PR #120: fix(api): drop manual Content-Length header so fetch does not fail under undici 7

Description (problem / solution / changelog)

Closes #119.

Summary

Content-Length is a forbidden request header in the WHATWG fetch spec — fetch is required to set it from the body and reject user-supplied values. Modern undici (Node 24's bundled 7.x) enforces this strictly: a manual Content-Length header triggers a synchronous InvalidArgumentError: invalid content-length header from request.processHeader, which surfaces to callers as the unhelpful TypeError: fetch failed and breaks openclaw channels login --channel openclaw-weixin (and any POST that flows through apiPostFetch).

Older undici versions silently stripped the user-supplied header, which is presumably why this only started biting on a recent OpenClaw / Node combo. Reported in openclaw/openclaw#78434.

Diff

src/api/api.ts buildHeaders(): remove the line

"Content-Length": String(Buffer.byteLength(opts.body, "utf-8")),

Fetch computes Content-Length from the body itself when one is supplied. Added a multi-line comment explaining why the line is intentionally absent so future contributors don't accidentally reintroduce it.

Regression test

Added in src/api/api.test.ts:

it("does not pass a manual Content-Length header to fetch", async () => {
  // ... assert mockFetch.mock.calls[0][1].headers has no content-length
});

Locks in the fix and prevents reintroduction.

Verification

Real reproduction from openclaw#78434:

openclaw plugins install '@tencent-weixin/[email protected]'
launchctl kickstart -k gui/$(id -u)/ai.openclaw.gateway
openclaw channels login --channel openclaw-weixin
# 正在启动...
# Failed to start login: TypeError: fetch failed

Captured the underlying cause by instrumenting apiPostFetch to log err.cause:

[diag] POST https://ilinkai.weixin.qq.com/ilink/bot/get_bot_qrcode?bot_type=3 err.cause= InvalidArgumentError: invalid content-length header
    at processHeader (.../node_modules/undici/lib/core/request.js:503:13)

After applying this patch and re-running the same login command, the QR code renders correctly:

正在启动...

用手机微信扫描以下二维码,以继续连接:

▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
█ ▄▄▄▄▄ █▄▄██████▄▀▀▄██▄ ▄▀▄█▀█ ▄▄▄▄▄ █
...

pnpm typecheck clean. pnpm exec vitest run src/api/api.test.ts → 14/14 passed (13 existing + 1 new regression test).

What did NOT change

  • No other endpoints touched. apiGetFetch already used buildCommonHeaders (no manual Content-Length). Long-poll getUpdates also goes through buildHeaders and benefits from this fix.
  • No body-construction change. Buffer.byteLength is no longer needed for header computation but no other code referenced it.
  • No bump to npm engines or undici dependency. The fix is spec-compliance, not a workaround for a specific undici version.

Changed files

  • src/api/api.test.ts (modified, +19/-0)
  • src/api/api.ts (modified, +6/-1)

Code Example

Failed to start login: TypeError: fetch failed
Channel login failed: Error: Failed to start login: TypeError: fetch failed

---

# Works perfectly (returns 200 with QR code data):
node -e "fetch('https://ilinkai.weixin.qq.com/ilink/bot/get_bot_qrcode?bot_type=3').then(r=>console.log(r.status)).catch(e=>console.log(e))"
# → 200

# Also works with the exact Gateway env vars:
NODE_EXTRA_CA_CERTS='/etc/ssl/cert.pem' NODE_USE_SYSTEM_CA='1' \
node -e "fetch('https://ilinkai.weixin.qq.com/ilink/bot/get_bot_qrcode?bot_type=3').then(r=>console.log(r.status)).catch(e=>console.log(e))"
# → 200

---

[INFO]  [runtime] setWeixinRuntime called, runtime set successfully
[INFO]  Starting Weixin login with bot_type=3
[INFO]  NewFetching QR code from: https://ilinkai.weixin.qq.com bot_type=3
[INFO]  newfetchQRCode: local_token_list count=0
[ERROR] Failed to start Weixin login: TypeError: fetch failed    ← 16ms after fetch initiated
[WARN]  auth.login: failed to get QR code accountId=default message=Failed to start login: TypeError: fetch failed
RAW_BUFFERClick to expand / collapse

Body

Environment

  • OpenClaw version: 2026.5.4 (325df3e)
  • Plugin version: @tencent-weixin/openclaw-weixin 2.4.1
  • Node.js: v24.14.0 (undici 7.21.0)
  • OS: macOS 15.4 (Darwin 25.4.0 arm64, Apple M3 Max)
  • Network: Direct connection (system proxy disabled, Clash Verge TUN off)

Problem

Running openclaw channels login --channel openclaw-weixin immediately fails with:

Failed to start login: TypeError: fetch failed
Channel login failed: Error: Failed to start login: TypeError: fetch failed

The plugin attempts to fetch https://ilinkai.weixin.qq.com/ilink/bot/get_bot_qrcode?bot_type=3 but fails within ~16ms (instant rejection, not a timeout).

Key Diagnostic Finding

The same fetch request succeeds when run outside the Gateway process:

# Works perfectly (returns 200 with QR code data):
node -e "fetch('https://ilinkai.weixin.qq.com/ilink/bot/get_bot_qrcode?bot_type=3').then(r=>console.log(r.status)).catch(e=>console.log(e))"
# → 200

# Also works with the exact Gateway env vars:
NODE_EXTRA_CA_CERTS='/etc/ssl/cert.pem' NODE_USE_SYSTEM_CA='1' \
node -e "fetch('https://ilinkai.weixin.qq.com/ilink/bot/get_bot_qrcode?bot_type=3').then(r=>console.log(r.status)).catch(e=>console.log(e))"
# → 200

But inside the Gateway process, the fetch fails immediately. This affects both notifyStart (ignored) and the QR code fetch (fatal for login).

Relevant Gateway Log Sequence

[INFO]  [runtime] setWeixinRuntime called, runtime set successfully
[INFO]  Starting Weixin login with bot_type=3
[INFO]  NewFetching QR code from: https://ilinkai.weixin.qq.com bot_type=3
[INFO]  newfetchQRCode: local_token_list count=0
[ERROR] Failed to start Weixin login: TypeError: fetch failed    ← 16ms after fetch initiated
[WARN]  auth.login: failed to get QR code accountId=default message=Failed to start login: TypeError: fetch failed

Investigation Notes

  1. DNS resolution worksdig ilinkai.weixin.qq.com resolves correctly; dns.lookup() in Node.js also succeeds.
  2. No proxy env vars in Gateway processHTTP_PROXY/HTTPS_PROXY are not set in the LaunchAgent env file.
  3. Problem persists across Gateway restarts — not a stale connection pool issue from long uptime.
  4. Timing: fails within 16ms of initiation = instant rejection, not network timeout.
  5. Suspicion: OpenClaw's ensureGlobalUndiciEnvProxyDispatcher() (in undici-global-dispatcher-BegCPCCN.js) or a global undici dispatcher state may interfere with the plugin's fetch() calls. The plugin uses standard global fetch() without any custom agent.
  6. eventLoopUtilization=1 reported by diagnostics during the failure, though actual CPU is <1% and health endpoint responds in 10ms.
  7. Other channels (Feishu, QQ Bot) work fine — their fetch calls succeed in the same Gateway process.

Steps to Reproduce

  1. Install @tencent-weixin/openclaw-weixin 2.4.1 on OpenClaw 2026.5.4
  2. Run openclaw channels login --channel openclaw-weixin
  3. Observe immediate TypeError: fetch failed

Expected Behavior

QR code should be fetched and displayed in terminal for scanning.

Workaround

None found. Uninstalled the plugin to avoid error log noise from auto-restart loop.

Questions

  • Is there a way to get the detailed cause of the fetch failure from the Gateway process?
  • Could the global undici dispatcher be interfering with plugin-initiated fetch calls?
  • Is this a known issue with 2026.5.4's undici integration?

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING