Skip to content

WeChat channel: all requests fail with 'TypeError: fetch failed' (manual Content-Length header rejected by undici) #55

Description

@yikkuro

Summary

The WeChat (weixin) channel silently fails: inbound messages are never answered and the WeChat client shows "暂无法连接 OpenClaw" (cannot connect to OpenClaw). The gateway logs a continuous stream of:

[openclaw-weixin] weixin getUpdates error (1/3): TypeError: fetch failed
[openclaw-weixin] weixin getUpdates error (2/3): TypeError: fetch failed
[openclaw-weixin] weixin getUpdates error (3/3): TypeError: fetch failed
[openclaw-weixin] weixin getUpdates: 3 consecutive failures, backing off 30s

and every outbound reply fails with:

outbound: FAILED to=...@im.wechat err=TypeError: fetch failed
sendMessageWeixin: failed ... err=TypeError: fetch failed
[weixin] typing send error: TypeError: fetch failed

Root cause

buildHeaders() in plugins/openclaw-weixin/src/api/api.ts sets a manual Content-Length header on every request:

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

The gateway runs on Node's bundled undici, which forbids setting Content-Length manually. undici throws:

InvalidArgumentError: invalid content-length header   (code: UND_ERR_INVALID_ARG)

This is wrapped by fetch as the generic TypeError: fetch failed, hiding the real cause. Because buildHeaders() is used by every API call (getUpdates, sendMessage, sendTyping, getConfig, getUploadUrl), the whole channel is broken.

Why it was hard to spot

  • The error message is only TypeError: fetch failed; the underlying err.cause (UND_ERR_INVALID_ARG) is not logged.
  • The identical request succeeds from a standalone Node process, because Node's top-level built-in fetch is more lenient about a manual Content-Length than the undici instance used inside the gateway. The failure only reproduces inside the running gateway.

The cause was captured by temporarily wrapping globalThis.fetch in the gateway to log err.cause, which revealed InvalidArgumentError: invalid content-length header.

Fix

Remove the manual Content-Length header and let fetch/undici compute it from the request body (which it does automatically for a string body).

Impact

Fixes all WeChat channel traffic: long-poll getUpdates, sendMessage, sendTyping, getConfig, and CDN upload URL requests.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions