zeroclaw-labs/zeroclaw · error · anyhow::Error
WeCom webhook send failed ({status}): {err}
Error message
WeCom webhook send failed ({status}): {err} What it means
The WeCom webhook channel POSTs the message payload to the robot's webhook URL; a non-2xx HTTP status bails with the status and body. It is raised in send(), which both outbound dispatch and health_check exercise, so a bad webhook surfaces immediately on health probes.
Source
Thrown at crates/zeroclaw-channels/src/wecom.rs:94
async fn send(&self, message: &SendMessage) -> anyhow::Result<()> {
let body = serde_json::json!({
"msgtype": "text",
"text": {
"content": message.content,
}
});
let resp = self
.http_client()
.post(self.webhook_url())
.json(&body)
.send()
.await?;
if !resp.status().is_success() {
let status = resp.status();
let err = resp.text().await.unwrap_or_default();
anyhow::bail!("WeCom webhook send failed ({status}): {err}");
}
// WeCom returns {"errcode":0,"errmsg":"ok"} on success.
let result: serde_json::Value = resp.json().await?;
let errcode = result.get("errcode").and_then(|v| v.as_i64()).unwrap_or(-1);
if errcode != 0 {
let errmsg = result
.get("errmsg")
.and_then(|v| v.as_str())
.unwrap_or("unknown error");
anyhow::bail!("WeCom API error (errcode={errcode}): {errmsg}");
}
Ok(())
}
async fn listen(&self, tx: tokio::sync::mpsc::Sender<ChannelMessage>) -> anyhow::Result<()> {
::zeroclaw_log::record!(View on GitHub (pinned to 88bb9c8533)
Solutions
- Verify the full webhook URL including ?key=... matches the currently issued robot webhook
- Act on the status: 404 → wrong URL/key; 413/payload errors → shorten the message; 5xx → retry later
- Read the embedded body — WeCom gateway errors are explicit about the cause
- Fix config before queueing more sends; use health_check to confirm the fix
Example fix
// before
let m = ChannelMessage::markdown(&scope, &huge_report); // gateway rejects size
// after
for chunk in split_markdown(&huge_report, 2000) {
channel.send(ChannelMessage::markdown(&scope, chunk)).await?;
} Defensive patterns
Strategy: retry
Try / catch
Parse the embedded status from 'WeCom webhook send failed': 404 → disable the channel and alert (bad key/URL); 413 → chunk the payload and resend; 5xx → retry with backoff, then dead-letter.
Prevention
- Run health_check right after any webhook config change to catch bad URLs before real traffic
- Chunk markdown/text payloads to stay under WeCom content limits
- Treat the webhook key as a rotating secret and update config when reissued
When it happens
Trigger: Calling send() or health_check() when the WeCom webhook endpoint answers 404 (wrong or rotated key in the URL), 413 (payload too large), or 5xx (WeCom gateway error).
Common situations: Webhook key regenerated in the WeCom admin console but not updated in channel config; copied URL truncated; markdown/text content exceeding WeCom's per-message size limit rejected at the gateway; WeCom API outage.
Related errors
- WeCom API error (errcode={errcode}): {errmsg}
- WeCom WS {command} ack timeout after {}s (req_id={req_id})
- WeCom attachment download failed: kind={} msg_id={} url_targ
- WeCom: invalid scope format: {scope}
- Failed to initiate call: {}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/17e440ac86941348.
Report an issue: GitHub.