chenhg5/cc-connect · error
wecom-ws: download HTTP %s
Error message
wecom-ws: download HTTP %s
What it means
downloadWeComWSMedia performs an HTTP GET of the WeCom media URL and requires a 2xx status. Any non-2xx response (404 expired URL, 403 denied, 5xx server error) is wrapped with the response status string via this error. The body is not decrypted, so callers get a clear network-layer failure.
Source
Thrown at platform/wecom/websocket_media.go:350
}
return filepath.Base(val)
}
return ""
}
func downloadWeComWSMedia(ctx context.Context, urlStr, aesKey string) (data []byte, fileName string, err error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, urlStr, nil)
if err != nil {
return nil, "", err
}
client := &http.Client{Timeout: 90 * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, "", err
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, "", fmt.Errorf("wecom-ws: download HTTP %s", resp.Status)
}
fileName = parseContentDispositionFilename(resp.Header.Get("Content-Disposition"))
lim := io.LimitReader(resp.Body, wecomWSMediaMaxBytes+1)
raw, err := io.ReadAll(lim)
if err != nil {
return nil, "", err
}
if len(raw) > wecomWSMediaMaxBytes {
return nil, "", fmt.Errorf("wecom-ws: media larger than %d bytes", wecomWSMediaMaxBytes)
}
if aesKey != "" {
raw, err = wecomDecryptFile(raw, aesKey)
if err != nil {
return nil, "", err
}
}
return raw, fileName, nil
}View on GitHub (pinned to 4000b2338a)
Solutions
- Re-fetch a fresh media URL from the WeCom API immediately before downloading; do not cache URLs.
- Check resp.Status in logs to distinguish 403 (permissions) from 404/410 (expired/deleted).
- Verify bot credentials/scopes if 401/403 persists, and check WeCom service status for 5xx.
Example fix
// before
url := cachedMediaURL[msgID] // minutes old
raw, err := downloadWeComWSMedia(url, key)
// after
url, err := fetchFreshMediaURL(msgID) // always fresh
if err != nil { return err }
raw, err := downloadWeComWSMedia(url, key) Defensive patterns
Strategy: retry
Validate before calling
if u, err := url.Parse(mediaURL); err != nil || u.Host == "" { return fmt.Errorf("bad media url") } Try / catch
raw, err := downloadWeComWSMedia(url, key)
if err != nil {
var herr *HTTPStatusError // or inspect status string
if strings.Contains(err.Error(), "404") || strings.Contains(err.Error(), "410") {
url, _ = fetchFreshMediaURL(msgID)
raw, err = downloadWeComWSMedia(url, key)
}
} Prevention
- Never cache WeCom media URLs; fetch fresh at download time.
- Distinguish 4xx (expired/forbidden) from 5xx (server) when retrying.
- Set a short HTTP timeout and verify bot credentials on repeated 401/403.
When it happens
Trigger: GET on the media URL returns 404/403/410/5xx — typically because the WeCom websocket media URL has expired (they are short-lived) or the bot lacks media access.
Common situations: Retrying a media URL minutes after receipt (expired); WeCom service incident; media deleted before download; misconfigured proxy returning an auth page.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- wecom-ws: media larger than %d bytes
- wecom: send message: %w
- range chunk retries exhausted
- wecom-ws: ack timeout
- request usage endpoint: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/2aed9f685af3afab.
Report an issue: GitHub.