chenhg5/cc-connect · error

%s: CDN upload server error: %s

Error message

%s: CDN upload server error: %s

What it means

uploadBufferToCDN records this error when the CDN returns a 5xx (or any non-200 outside 400-499) status. It is stored as lastErr and the loop retries up to cdnUploadMaxRetries (3) attempts before surfacing the wrapped error via the 'failed after N attempts' message. The reason is taken from the x-error-message header or 'status <code>'.

Source

Thrown at platform/weixin/cdn.go:210

			lastErr = err
			slog.Warn("weixin: CDN upload request failed", "label", label, "attempt", attempt, "error", err)
			continue
		}
		_, _ = io.Copy(io.Discard, io.LimitReader(resp.Body, 4096))
		_ = resp.Body.Close()
		if resp.StatusCode >= 400 && resp.StatusCode < 500 {
			msg := resp.Header.Get("x-error-message")
			if msg == "" {
				msg = resp.Status
			}
			return "", fmt.Errorf("%s: CDN upload client error %d: %s", label, resp.StatusCode, msg)
		}
		if resp.StatusCode != http.StatusOK {
			msg := resp.Header.Get("x-error-message")
			if msg == "" {
				msg = fmt.Sprintf("status %d", resp.StatusCode)
			}
			lastErr = fmt.Errorf("%s: CDN upload server error: %s", label, msg)
			slog.Warn("weixin: CDN upload server error", "label", label, "attempt", attempt, "error", lastErr)
			continue
		}
		dl := resp.Header.Get("x-encrypted-param")
		if dl == "" {
			lastErr = fmt.Errorf("%s: CDN response missing x-encrypted-param", label)
			slog.Warn("weixin: CDN upload bad response", "label", label, "attempt", attempt)
			continue
		}
		return dl, nil
	}
	if lastErr != nil {
		return "", fmt.Errorf("%s: CDN upload failed after %d attempts: %w", label, cdnUploadMaxRetries, lastErr)
	}
	return "", fmt.Errorf("%s: CDN upload failed after %d attempts", label, cdnUploadMaxRetries)
}

func md5Hex(b []byte) string {

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Retry the operation — server errors are transient and the function already retries 3 times; the wrapped lastErr shows the final reason
  2. Check the x-error-message/status in the error text for the specific 5xx code
  3. Verify network connectivity and DNS resolution to the CDN host
  4. If persistent, check WeChat service status or reduce media size/frequency

Example fix

// before: treating every upload failure as fatal
if err := uploadToWeixinCDN(ctx, ...); err != nil { return err }
// after: tolerate transient server errors with backoff at the caller
if err := uploadToWeixinCDN(ctx, ...); err != nil {
    if strings.Contains(err.Error(), "server error") { time.Sleep(time.Second); return uploadToWeixinCDN(ctx, ...) }
    return err
}
Defensive patterns

Strategy: retry

Validate before calling

// check reachability before a batch of uploads
resp, err := http.Get("https://novac2c.cdn.weixin.qq.com/c2c/healthz") // or any cheap probe
if err != nil { /* defer uploads or use fallback */ }

Try / catch

// the library already retries 3x; add caller backoff
if err != nil && strings.Contains(err.Error(), "CDN upload server error") {
    time.Sleep(2 * time.Second)
    // retry once more
}

Prevention

When it happens

Trigger: Any CDN upload POST returning HTTP >= 500 (or non-200 outside 400-499), e.g. 500, 502, 503 from the CDN edge; each attempt logs slog.Warn then continues.

Common situations: Transient CDN outages or capacity issues; CDN edge nodes returning 502/504; maintenance windows on novac2c.cdn.weixin.qq.com.

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/1b0804a7e5421784. Report an issue: GitHub.