chenhg5/cc-connect · error
read upload response: %w
Error message
read upload response: %w
What it means
This error wraps an io.ReadAll failure that occurred while reading the body of the HTTP response from DingTalk's media upload endpoint. The upload request itself was sent successfully, but the response body could not be fully read, typically because the connection was interrupted or reset mid-transfer. It is thrown by the DingTalk platform's media upload helper (returning "", err) whenever the response body stream errors.
Source
Thrown at platform/dingtalk/dingtalk.go:1378
return "", fmt.Errorf("close multipart writer: %w", err)
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadURL, body)
if err != nil {
return "", fmt.Errorf("create upload request: %w", err)
}
req.Header.Set("Content-Type", writer.FormDataContentType())
resp, err := p.httpClient.Do(req)
if err != nil {
return "", fmt.Errorf("upload request: %w", err)
}
defer func() { _ = resp.Body.Close() }()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("read upload response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("upload returned status %d: %s", resp.StatusCode, respBody)
}
slog.Debug("dingtalk: media upload response", "status", resp.StatusCode, "body", string(respBody))
var uploadResp struct {
ErrCode int `json:"errcode"`
ErrMsg string `json:"errmsg"`
MediaID string `json:"media_id"`
Type string `json:"type"`
}
if err := json.Unmarshal(respBody, &uploadResp); err != nil {
return "", fmt.Errorf("decode upload response: %w, body: %s", err, respBody)
}
View on GitHub (pinned to 4000b2338a)
Solutions
- Check network connectivity and any corporate proxy/VPN between the host and DingTalk's API (oapi.dingtalk.com / api.dingtalk.com).
- Retry the send — the underlying error is often transient, so a subsequent upload attempt may succeed.
- Reduce the media file size or re-encode it so the response window is shorter.
- If a custom HTTP client/transport is used, verify read timeouts are not too aggressive for large uploads.
- Capture the wrapped error (%w) with errors.Unwrap or errors.Is to identify the exact net/http root cause (connection reset, EOF, timeout).
Example fix
// before
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("read upload response: %w", err)
}
// after
respBody, err := io.ReadAll(resp.Body)
if err != nil {
slog.Warn("dingtalk: media upload response read failed, will surface to caller", "err", err)
return "", fmt.Errorf("read upload response: %w", err)
} Defensive patterns
Strategy: retry
Validate before calling
// precondition check before upload
if len(data) == 0 {
return fmt.Errorf("nothing to upload")
}
// ensure client has sane timeout
client := &http.Client{Timeout: 60 * time.Second} Type guard
func isTransientReadErr(err error) bool {
var ne net.Error
return errors.As(err, &ne) || errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF)
} Try / catch
mediaID, err := uploadMedia(ctx, data, mediaType)
if err != nil {
if isTransientReadErr(errors.Unwrap(err)) {
// retry once after backoff
time.Sleep(2 * time.Second)
mediaID, err = uploadMedia(ctx, data, mediaType)
}
if err != nil {
slog.Error("media upload failed reading response", "err", err)
return err
}
} Prevention
- Set a generous but bounded http.Client timeout for uploads.
- Run cc-connect on a host with stable egress; avoid flaky VPNs for production.
- Keep media files small to shorten the network window.
- Monitor logs for repeated read errors indicating infra-level network problems.
When it happens
Trigger: Calling the media upload path (image/file/voice/video send) when io.ReadAll(resp.Body) returns a non-nil error — e.g. the TCP connection to DingTalk's upload host is closed or reset before the body completes, a proxy/VPN severs the stream, or a read deadline elapses partway through.
Common situations: Corporate proxies or firewalls killing long-running uploads; flaky mobile/office networks; very large media files whose download phase outlives a NAT or idle-timeout window; Docker/Kubernetes DNS or egress interruptions.
Related errors
- upload request: %w
- read body from %s: %w
- read body from %s: %w
- read response: %w
- qwen tts: read audio: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/d3aa0f336ae4a464.
Report an issue: GitHub.