chenhg5/cc-connect · info

googlechat: upload: create media part: %w

Error message

googlechat: upload: create media part: %w

What it means

Returned by uploadAttachment when multipart.Writer.CreatePart fails while creating the media part for the uploaded file. CreatePart only fails on an invalid MIME header; since the header is just the provided mimeType string, this is practically unreachable with stock code unless mimeType contains illegal header characters. It surfaces via postAttachment from SendImage/SendFile.

Source

Thrown at platform/googlechat/googlechat.go:468

}

// uploadAttachment uploads raw bytes to the Chat media endpoint using a
// multipart/related request and returns the attachmentDataRef resource name.
func (p *Platform) uploadAttachment(ctx context.Context, space, filename, mimeType string, data []byte) (string, error) {
	buf := bytes.NewBuffer(make([]byte, 0, 256+len(data)))
	mw := multipart.NewWriter(buf)

	metaPart, err := mw.CreatePart(textproto.MIMEHeader{"Content-Type": {"application/json; charset=UTF-8"}})
	if err != nil {
		return "", fmt.Errorf("googlechat: upload: create metadata part: %w", err)
	}
	if err := json.NewEncoder(metaPart).Encode(map[string]string{"filename": filename}); err != nil {
		return "", fmt.Errorf("googlechat: upload: encode metadata: %w", err)
	}

	mediaPart, err := mw.CreatePart(textproto.MIMEHeader{"Content-Type": {mimeType}})
	if err != nil {
		return "", fmt.Errorf("googlechat: upload: create media part: %w", err)
	}
	if _, err := mediaPart.Write(data); err != nil {
		return "", fmt.Errorf("googlechat: upload: write media: %w", err)
	}
	if err := mw.Close(); err != nil {
		return "", fmt.Errorf("googlechat: upload: finalize multipart body: %w", err)
	}

	uploadURL := chatUploadBase + space + "/attachments:upload?uploadType=multipart"
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadURL, buf)
	if err != nil {
		return "", fmt.Errorf("googlechat: upload: build request: %w", err)
	}
	req.Header.Set("Content-Type", "multipart/related; boundary="+mw.Boundary())

	resp, err := p.doRequest(req)
	if err != nil {
		return "", err

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Sanitize or hardcode the mimeType (e.g. use mime.TypeByExtension or a fixed allowlist like image/png).
  2. Strip newlines/control characters from any dynamically computed mimeType before passing it in.
  3. Validate mimeType in config at startup if it comes from config.toml.

Example fix

// before
mime := cfg.MimeType // user-provided, may contain "\n"
// after
mime = strings.Map(func(r rune) rune {
    if r < 32 || r == 127 { return -1 }
    return r
}, cfg.MimeType)
Defensive patterns

Strategy: validation

Validate before calling

// validate mimeType before calling SendFile/SendImage
mime := cfg.MimeType
if mime == "" || !strings.Contains(mime, "/") || strings.ContainsAny(mime, " \t\r\n\x00") {
    return fmt.Errorf("invalid mimeType %q", mime)
}

Type guard

func isValidMimeType(m string) bool {
    parts := strings.SplitN(m, "/", 2)
    return len(parts) == 2 && parts[0] != "" && parts[1] != "" &&
        !strings.ContainsAny(m, " \t\r\n\x00")
}

Prevention

When it happens

Trigger: Calling SendImage()/SendFile() with a mimeType containing characters illegal in an HTTP header (e.g. newlines, control chars) can make CreatePart return an error.

Common situations: Config mistakes where mimeType is user-supplied or derived from an untrusted filename extension and contains whitespace/newlines.

Related errors


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