chenhg5/cc-connect · error
cdn upload: %w
Error message
cdn upload: %w
What it means
This is the transport-level failure branch of the second step of MAX's two-step attachment upload: the multipart/form-data POST of the file bytes to the presigned CDN URL. When p.uploadClient.Do returns a non-nil error (connection failure, TLS error, DNS failure, timeout, context cancellation), the error is wrapped with the "cdn upload: " prefix and returned. It is a network/client-side failure, not an HTTP status error.
Source
Thrown at platform/max/max.go:596
return "", err
}
if _, err := fw.Write(data); err != nil {
return "", err
}
if err := mw.Close(); err != nil {
return "", err
}
cdnReq, err := http.NewRequestWithContext(uploadCtx, http.MethodPost, urlInfo.URL, &buf)
if err != nil {
return "", err
}
p.setAuth(cdnReq)
cdnReq.Header.Set("Content-Type", mw.FormDataContentType())
cdnResp, err := p.uploadClient.Do(cdnReq)
if err != nil {
return "", fmt.Errorf("cdn upload: %w", err)
}
defer cdnResp.Body.Close()
if cdnResp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(io.LimitReader(cdnResp.Body, 512))
return "", fmt.Errorf("cdn upload: HTTP %d: %s", cdnResp.StatusCode, body)
}
cdnBody, err := io.ReadAll(io.LimitReader(cdnResp.Body, 64*1024))
if err != nil {
return "", fmt.Errorf("read cdn response: %w", err)
}
// MAX CDN uses different response shapes per attachment kind:
// image: {"photos": {"<photo_id>": {"token": "..."}}}
// file: {"token": "..."}
// video/audio: "<retval>1</retval>" (XML) — the real token is already in urlInfo.Token
if token := extractCDNToken(kind, cdnBody); token != "" {
return token, nil
}
if urlInfo.Token != "" {View on GitHub (pinned to 4000b2338a)
Solutions
- Check network reachability of the CDN URL host returned by /uploads (curl -v to it) — proxies and firewalls commonly block it.
- Reduce attachment size or increase attachmentUploadTO if large files routinely time out on your network.
- Confirm the caller's context isn't already near expiry; the upload inherits the session context deadline.
- Retry the upload with backoff — CDN transport failures are often transient.
- If behind a corporate proxy, configure the uploadClient's Proxy/Transport to route through it.
Example fix
// before
err := p.uploadAttachment(ctx, "image", data, "photo.png")
// after (pre-flight size check + bounded retry)
const maxUpload = 50 << 20 // 50 MiB
if len(data) > maxUpload {
return fmt.Errorf("attachment too large: %d bytes", len(data))
}
var token string
var lastErr error
for attempt := 0; attempt < 3; attempt++ {
token, lastErr = p.uploadAttachment(ctx, "image", data, "photo.png")
if lastErr == nil {
break
}
var netErr net.Error
if errors.As(lastErr, &netErr) && netErr.Timeout() {
time.Sleep(time.Duration(attempt+1) * time.Second)
continue
}
break
} Defensive patterns
Strategy: retry
Validate before calling
// Reachability pre-check before uploading
func cdnReachable(uploadClient *http.Client, url string) bool {
u, err := neturl.Parse(url)
if err != nil || u.Host == "" { return false }
conn, err := net.DialTimeout("tcp", u.Host, 3*time.Second)
if err != nil { return false }
conn.Close()
return true
} Type guard
var _ net.Error
func isTimeoutOrCancel(err error) bool {
return errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) || (func() bool { var n net.Error; return errors.As(err, &n) && n.Timeout() })()
} Try / catch
token, err := p.uploadAttachment(ctx, kind, data, filename)
if err != nil {
var nerr net.Error
if errors.As(err, &nerr) && nerr.Timeout() {
// bounded retry with backoff for transient transport failures
}
if errors.Is(err, context.Canceled) {
return fmt.Errorf("max: upload canceled: %w", err)
}
} Prevention
- Size-limit attachments client-side before upload; large files are the top timeout cause.
- Use wired/stable networks for bulk uploads; check proxy/firewall rules for the CDN host.
- Keep the caller's context alive long enough to cover the 5-minute upload window.
- Add exponential backoff retries around SendImage/SendFile/SendAudio.
When it happens
Trigger: Calling SendImage/SendFile/SendAudio when the CDN endpoint is unreachable, the 5-minute attachmentUploadTO deadline or caller context expires mid-upload, TLS handshake fails, DNS resolution fails, or the connection is reset while streaming the multipart body for large files.
Common situations: Uploading large files over slow links hitting the 5-minute timeout; firewall/proxy blocking the CDN host returned by /uploads; transient CDN outages; IPv6 connectivity issues; mobile/offline networks; canceling the enclosing session context.
Related errors
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/90315e3acbdbd2ba.
Report an issue: GitHub.