chenhg5/cc-connect · error
empty attachment data
Error message
empty attachment data
What it means
uploadAttachment rejects calls where the data slice is empty before doing any network work. The two-step MAX upload (request upload URL, then multipart POST) is pointless with zero bytes, so the library fails fast with this sentinel error. It indicates the caller passed no attachment payload.
Source
Thrown at platform/max/max.go:534
resp, err := p.client.Do(req)
if err != nil {
return fmt.Errorf("max: edit message: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
respBody, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
return fmt.Errorf("max: edit message: HTTP %d: %s", resp.StatusCode, respBody)
}
return nil
}
// uploadAttachment performs the two-step MAX upload: request an upload URL from
// /uploads?type=<kind>, then POST the binary as multipart/form-data field "data"
// to that URL. Returns the token to embed in a subsequent /messages attachment.
func (p *Platform) uploadAttachment(ctx context.Context, kind string, data []byte, filename string) (string, error) {
if len(data) == 0 {
return "", fmt.Errorf("empty attachment data")
}
// Use a 5-minute context AND a dedicated http.Client with a matching Timeout.
// p.client has a 35 s Timeout which fires independently of the context deadline
// and would abort large CDN uploads before the context expires.
uploadCtx, cancel := context.WithTimeout(ctx, attachmentUploadTO)
defer cancel()
urlReq, err := http.NewRequestWithContext(uploadCtx, http.MethodPost, p.apiBase+"/uploads", nil)
if err != nil {
return "", err
}
p.setAuth(urlReq)
q := urlReq.URL.Query()
q.Set("type", kind)
urlReq.URL.RawQuery = q.Encode()
urlResp, err := p.uploadClient.Do(urlReq)
if err != nil {View on GitHub (pinned to 4000b2338a)
Solutions
- Check the source of the attachment data — the upstream read probably silently produced an empty slice
- Guard before calling: if len(data) == 0 { skip or return a descriptive error }
- If the file is legitimately empty, decide policy: skip sending rather than call the API
- Log the attachment filename/source to find why it is empty
Example fix
// before
token, err := p.uploadAttachment(ctx, "image", data, "pic.png")
// after
if len(data) == 0 {
return fmt.Errorf("max: skipping %s: empty attachment data", filename)
}
token, err := p.uploadAttachment(ctx, "image", data, "pic.png") Defensive patterns
Strategy: validation
Validate before calling
if len(data) == 0 { return fmt.Errorf("attachment %s is empty", filename) } Try / catch
if err != nil && strings.Contains(err.Error(), "empty attachment data") {
slog.Warn("skipping empty attachment", "file", filename)
return nil
} Prevention
- Always check the error return of file reads before using the bytes
- Verify file size > 0 with os.Stat before sending
- Skip or placeholder-replace empty attachments instead of calling the upload path
When it happens
Trigger: Calling SendImage, SendFile, or SendAudio with an empty []byte payload — typically after a failed file read that returned (nil, nil), an unmarshaled attachment with no Data field, or a zero-length download.
Common situations: Reading a local file that exists but is 0 bytes; forgetting to check err before using file content from ioutil.ReadFile in an upstream wrapper; attachments forwarded from another platform with no body downloaded.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- empty media data
- weixin: getUploadUrl: empty upload_param and upload_full_url
- weixin: %s: empty payload
- message, tts_text, or attachment is required
- app_id/app_secret are required
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/f63bd11dfc1b400e.
Report an issue: GitHub.