chenhg5/cc-connect · error
cdn upload: HTTP %d: %s
Error message
cdn upload: HTTP %d: %s
What it means
The MAX CDN returned a non-200 HTTP status to the multipart upload POST. The platform reads up to 512 bytes of the response body and reports the status code plus a truncated body so the developer can see the CDN's own error message. This means the upload request reached the CDN and was rejected (auth, payload, or URL problems), not a transport failure.
Source
Thrown at platform/max/max.go:601
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 != "" {
return urlInfo.Token, nil
}
return "", fmt.Errorf("cdn upload: no token in response: %s", cdnBody)
}
View on GitHub (pinned to 4000b2338a)
Solutions
- Read the truncated body in the error — it contains the CDN's specific reason (auth vs. size vs. bad request).
- Minimize the delay between the /uploads call and the CDN POST; regenerate the upload URL if more than a few minutes elapsed.
- Verify the bot token is still valid and has upload permissions; re-test step 1 alone with curl.
- Check the file size against MAX's attachment limits per kind and compress or truncate as needed.
- Ensure the multipart field name is exactly "data" and Content-Type comes from mw.FormDataContentType() — deviations cause 400s.
Example fix
// before
urlInfo, err := getUploadURL(...)
// ... long processing ...
token, err := p.uploadAttachment(ctx, kind, data, filename) // URL may be stale
// after: fetch upload URL and POST back-to-back
urlInfo, err := requestUploadURL(ctx, kind)
if err != nil {
return fmt.Errorf("max: get upload url: %w", err)
}
token, err := p.uploadAttachment(ctx, kind, data, filename)
if err != nil {
return fmt.Errorf("max: upload %s: %w", kind, err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check size against a conservative MAX attachment cap before uploading
const maxAttachmentBytes = 30 << 20
if len(data) > maxAttachmentBytes {
return fmt.Errorf("attachment %s too large: %d > %d bytes", filename, len(data), maxAttachmentBytes)
} Try / catch
token, err := p.uploadAttachment(ctx, kind, data, filename)
if err != nil {
var statusErr interface{ HTTPStatus() int }
if strings.Contains(err.Error(), "cdn upload: HTTP ") {
// parse status; regenerate upload URL and retry once on 4xx
if newURL, uerr := requestUploadURL(ctx, kind); uerr == nil {
_ = newURL
}
}
} Prevention
- Upload immediately after requesting the upload URL — presigned URLs expire.
- Respect per-kind size limits; compress images before sending.
- Keep bot tokens valid; most CDN 401/403s trace back to expired credentials.
- Keep the multipart field name "data" and use mw.FormDataContentType() exactly.
When it happens
Trigger: SendImage/SendFile/SendAudio where the CDN answers e.g. 401/403 (setAuth token invalid or expired), 400 (malformed multipart, wrong Content-Type, missing "data" field), 404 (the presigned URL expired between step 1 and step 2), or 413 (payload too large).
Common situations: Delaying too long between obtaining the upload URL and POSTing the file (presigned URL expiry); uploading files exceeding the CDN's per-kind size cap; revoked bot tokens; sending a kind mismatched with the URL (e.g. image bytes to a file-type URL).
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
- upload url: HTTP %d: %s
- upload url: empty url in response
- upload returned status %d: %s
- max: edit message: HTTP %d: %s
- cdn upload: no token in response: %s
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/0265ba24cb01ff03.
Report an issue: GitHub.