chenhg5/cc-connect · error

close multipart writer: %w

Error message

close multipart writer: %w

What it means

multipart.Writer.Close() failed when finalizing the upload body for the DingTalk media API. Close flushes the closing boundary; failure here means the multipart body is incomplete and the request must not be sent.

Source

Thrown at platform/dingtalk/dingtalk.go:1360

		return "", fmt.Errorf("get access token: %w", err)
	}

	uploadURL := fmt.Sprintf("https://oapi.dingtalk.com/media/upload?access_token=%s&type=%s", token, mediaType)

	body := bytes.NewBuffer(nil)
	writer := multipart.NewWriter(body)

	part, err := writer.CreateFormFile("media", fileName)
	if err != nil {
		return "", fmt.Errorf("create form file: %w", err)
	}

	if _, err := part.Write(data); err != nil {
		return "", fmt.Errorf("write media data: %w", err)
	}

	if err := writer.Close(); err != nil {
		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)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Ensure Close is called exactly once, after all parts are written.
  2. If Close fails, abandon the body and rebuild it — a half-closed multipart body yields server-side parse errors.
  3. For large media, write to a temp file sink instead of an in-memory buffer to avoid allocation failures.

Example fix

// before
defer writer.Close()
...
req, _ := http.NewRequestWithContext(ctx, "POST", uploadURL, body) // may race Close
// after
if err := writer.Close(); err != nil { return "", fmt.Errorf("close multipart writer: %w", err) }
req, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadURL, body)
Defensive patterns

Strategy: try-catch

Try / catch

if err := writer.Close(); err != nil {
    return "", fmt.Errorf("close multipart writer: %w", err) // do NOT send the request
}

Prevention

When it happens

Trigger: writer.Close() returns an error in uploadMedia after all parts were written — typically an underlying buffer write failure or calling Close after the writer was already closed.

Common situations: Double-Close after a refactor; memory pressure on huge media bodies; custom io.Writer sink that errors on flush.

Related errors


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