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

  1. Check the source of the attachment data — the upstream read probably silently produced an empty slice
  2. Guard before calling: if len(data) == 0 { skip or return a descriptive error }
  3. If the file is legitimately empty, decide policy: skip sending rather than call the API
  4. 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

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


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