zeroclaw-labs/zeroclaw · error
WeCom attachment download failed: kind={} msg_id={} url_targ
Error message
WeCom attachment download failed: kind={} msg_id={} url_target={} status={} body_preview={} What it means
WeCom WS attachment downloads fetch the media URL and require a 2xx status; failures bail with a log-style message including the attachment kind, msg_id, a summarized URL target (via summarize_attachment_url_for_log), the HTTP status, and a 512-character body preview (truncate_for_log).
Source
Thrown at crates/zeroclaw-channels/src/wecom_ws.rs:1322
let response = self
.client
.get(url)
.send()
.await
.with_context(|| {
format!(
"failed to download WeCom attachment: kind={} msg_id={} url_target={} elapsed_ms={}",
kind.as_str(),
inbound.msg_id,
url_target,
started.elapsed().as_millis(),
)
})?;
let status = response.status();
if !status.is_success() {
let body = response.text().await.unwrap_or_default();
let body_preview = truncate_for_log(&body, 512);
anyhow::bail!(
"WeCom attachment download failed: kind={} msg_id={} url_target={} status={} body_preview={}",
kind.as_str(),
inbound.msg_id,
url_target,
status,
body_preview
);
}
if let Some(len) = response.content_length()
&& len > self.cfg.max_file_size_bytes
{
wecom_log_warn!(
"WeCom attachment skipped: declared size exceeds configured limit msg_id={} attachment_kind={} declared_bytes={} max_file_size_bytes={}",
inbound.msg_id,
kind.as_str(),
len,
self.cfg.max_file_size_bytesView on GitHub (pinned to 88bb9c8533)
Solutions
- Read the embedded status and body preview: 403/expired → process attachments promptly or skip; 404 → media gone, request a resend; 5xx → retry with backoff
- Retry the download a bounded number of times for 5xx only
- Compare url_target in the message against the expected media host to spot proxy rewrites
Defensive patterns
Strategy: retry
Try / catch
Branch on the embedded status: 5xx → bounded retry with backoff; 403/404 (expired/gone media) → skip the attachment, log msg_id, and continue processing the message; anything else → log the body preview and dead-letter.
Prevention
- Process inbound WeCom attachments immediately rather than queueing long — signed URLs expire
- Ensure proxies do not rewrite media URLs or strip auth headers (check the logged url_target)
- Cap retries so permanently expired media is dropped with a log entry, not a loop
When it happens
Trigger: An inbound WeCom message with media (image/file/voice) whose download URL returns 403 (expired URL or auth), 404 (media no longer retained), or 5xx (CDN/gateway error).
Common situations: Delayed processing after the signed media URL expired; wrong media proxy config; WeCom CDN issues; a proxy stripping auth headers or rewriting the URL (visible in url_target).
Related errors
- attachment download failed ({status}): {body}
- inbound attachment exceeds {} MB limit
- audio download failed: {}
- audio download failed ({status}) for message {message_id}
- refusing non-HTTPS attachment URL: {url}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/7ff693965d15c63b.
Report an issue: GitHub.