chenhg5/cc-connect · error

read cdn response: %w

Error message

read cdn response: %w

What it means

After a 200 from the CDN upload POST, uploadAttachment reads up to 64 KiB of the response body to extract the attachment token. If that read fails (connection reset mid-response, context deadline exceeded while reading, chunked-body corruption), the error is wrapped as "read cdn response: %w". The upload itself succeeded server-side, but the token needed for the follow-up /messages attachment could not be retrieved.

Source

Thrown at platform/max/max.go:605

	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)
}

// extractCDNToken parses the token out of a MAX CDN upload response. Returns
// "" if not found; the caller is expected to fall back to urlInfo.Token.
func extractCDNToken(kind string, body []byte) string {
	switch kind {

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Retry the whole upload — since the CDN likely stored the file, a fresh upload replaces it cleanly.
  2. Check network stability to the CDN host (packet loss, MTU issues with VPNs).
  3. Verify the 5-minute context isn't being preemptively canceled by the caller.
  4. If it recurs with one CDN host, log the host and report it; consider pinning IPv4 in the Transport if IPv6 is flaky.

Example fix

// before
var token string
var err error
token, err = p.uploadAttachment(ctx, kind, data, filename)
// after: bounded retry for transient read failures
var token string
var err error
for i := 0; i < 2; i++ {
	token, err = p.uploadAttachment(ctx, kind, data, filename)
	if err == nil || !strings.Contains(err.Error(), "read cdn response") {
		break
	}
	time.Sleep(time.Second)
}
Defensive patterns

Strategy: retry

Validate before calling

// Ensure the upload context has enough headroom before starting
if deadline, ok := ctx.Deadline(); ok && time.Until(deadline) < attachmentUploadTO {
	return fmt.Errorf("insufficient context budget for upload: %v left", time.Until(deadline))
}

Type guard

func isReadFailure(err error) bool {
	return strings.Contains(err.Error(), "read cdn response:")
}

Try / catch

token, err := p.uploadAttachment(ctx, kind, data, filename)
if err != nil {
	if strings.Contains(err.Error(), "read cdn response:") {
		// retry once: transient stream interruption, full re-upload is idempotent
		time.Sleep(time.Second)
		token, err = p.uploadAttachment(ctx, kind, data, filename)
	}
}

Prevention

When it happens

Trigger: SendImage/SendFile/SendAudio where the CDN's 200 response body cannot be fully read within the 5-minute upload context — typically connection reset by the CDN, context cancellation, or a stalled/slow response stream.

Common situations: Unstable networks interrupting the response; CDN servers under load returning truncated chunked responses; the 5-minute attachmentUploadTO deadline firing during the read of a very large response (rare, since the body is capped at 64 KiB).

Related errors


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