chenhg5/cc-connect · error
%s: CDN upload failed after %d attempts: %w
Error message
%s: CDN upload failed after %d attempts: %w
What it means
Final error returned by uploadBufferToCDN after exhausting cdnUploadMaxRetries (3) attempts. It wraps the last underlying failure (lastErr) — a transport error, 5xx server error, or missing x-encrypted-param — so the root cause appears after 'attempts:'.
Source
Thrown at platform/weixin/cdn.go:223
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 {
h := md5.Sum(b)
return hex.EncodeToString(h[:])
}
func detectImageMime(b []byte) string {
if len(b) >= 3 && b[0] == 0xFF && b[1] == 0xD8 && b[2] == 0xFF {
return "image/jpeg"
}
if len(b) >= 8 && string(b[0:8]) == "\x89PNG\r\n\x1a\n" {
return "image/png"
}
if len(b) >= 6 && (string(b[0:6]) == "GIF87a" || string(b[0:6]) == "GIF89a") {
return "image/gif"View on GitHub (pinned to 4000b2338a)
Solutions
- Read the wrapped %w cause after 'attempts:' to see the actual failure (transport vs server error vs missing header)
- If it's a network error, check connectivity/DNS/proxy to the CDN host and retry later
- If it's 'server error', wait for the CDN side to recover or add caller-level backoff with longer delays
- If it's 'missing x-encrypted-param' on every attempt, verify cdn_base configuration and API-version compatibility
Example fix
// before: no caller backoff
err := uploadToWeixinCDN(ctx, data, key)
// after: exponential backoff around the 3 built-in attempts
var err error
for d := time.Second; d <= 8*time.Second; d *= 2 {
if err = uploadToWeixinCDN(ctx, data, key); err == nil { break }
time.Sleep(d)
} Defensive patterns
Strategy: retry
Validate before calling
// pre-flight network sanity check before large uploads
if _, err := net.LookupHost("novac2c.cdn.weixin.qq.com"); err != nil { /* postpone upload */ } Try / catch
var err error
for d := time.Second; d <= 8*time.Second; d *= 2 {
if err = uploadToWeixinCDN(ctx, data, key); err == nil { break }
time.Sleep(d)
}
if err != nil { log.Printf("upload permanently failed: %v", err) } Prevention
- Run uploads on hosts with stable connectivity to the CDN
- Parse the wrapped cause after 'attempts:' to route fixes (network vs server vs contract)
- Queue and retry media uploads in the background instead of failing user messages synchronously
- Cap media size well under 100 MiB to reduce upload failure windows
When it happens
Trigger: All 3 upload attempts failed with retryable errors: client.Do transport failures, HTTP >= 500, or 200 responses missing x-encrypted-param.
Common situations: Sustained CDN outage; network partition between the bot host and novac2c.cdn.weixin.qq.com; persistent response-contract mismatch (every 200 lacks the header).
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- %s: CDN upload client error %d: %s
- %s: CDN response missing x-encrypted-param
- %s: CDN upload failed after %d attempts
- refresh QR: %w
- http %d: %s
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/33e569032039df24.
Report an issue: GitHub.