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

  1. Re-fetch a fresh media URL from the WeCom API immediately before downloading; do not cache URLs.
  2. Check resp.Status in logs to distinguish 403 (permissions) from 404/410 (expired/deleted).
  3. 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

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


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/2aed9f685af3afab. Report an issue: GitHub.