chenhg5/cc-connect · error

max: upload file: %w

Error message

max: upload file: %w

What it means

Wrapped failure from uploadAttachment when sending a file (kind derived from MIME type as file/image/video/audio): the attachment upload failed, so no token is available for the send body.

Source

Thrown at platform/max/max.go:458

	rctx, ok := replyCtx.(replyContext)
	if !ok {
		return fmt.Errorf("max: unexpected replyCtx type %T", replyCtx)
	}
	kind := "file"
	attType := "file"
	if strings.HasPrefix(file.MimeType, "image/") {
		kind = "image"
		attType = "image"
	} else if strings.HasPrefix(file.MimeType, "video/") {
		kind = "video"
		attType = "video"
	} else if strings.HasPrefix(file.MimeType, "audio/") {
		kind = "audio"
		attType = "audio"
	}
	token, err := p.uploadAttachment(ctx, kind, file.Data, file.FileName)
	if err != nil {
		return fmt.Errorf("max: upload file: %w", err)
	}
	body := &maxSendBody{
		Attachments: []maxOutAttachment{{
			Type:    attType,
			Payload: maxTokenPayload{Token: token},
		}},
	}
	return p.postMessage(ctx, rctx.chatID, body)
}

// SendAudio implements core.AudioSender — uploads a voice/audio blob and sends
// it as a native MAX audio attachment. Used by the TTS pipeline to reply in
// voice when [tts] is enabled in config.
func (p *Platform) SendAudio(ctx context.Context, replyCtx any, audio []byte, format string) error {
	rctx, ok := replyCtx.(replyContext)
	if !ok {
		return fmt.Errorf("max: unexpected replyCtx type %T", replyCtx)
	}

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Read the wrapped error's status: 401/403 → token; 413 → reduce file size; 415 → unsupported type.
  2. Confirm file.Data is complete and file.FileName includes a valid extension.
  3. Retry transient network/5xx failures; nothing was sent yet so retries are safe.
  4. Check MimeType so images/audio are uploaded with the correct kind for previews.
Defensive patterns

Strategy: retry

Validate before calling

if len(file.Data) == 0 { return errors.New("empty file data") }
if file.FileName == "" || filepath.Ext(file.FileName) == "" { return errors.New("file name missing extension") }

Try / catch

if err := p.SendFile(ctx, replyCtx, file); err != nil {
    if strings.Contains(err.Error(), "upload file") {
        if isRetryable(err) {
            retryWithBackoff(func() error { return p.SendFile(ctx, replyCtx, file) })
        } else {
            slog.Error("file upload rejected", "err", err)
        }
    }
}

Prevention

When it happens

Trigger: SendFile called with empty or oversized file.Data, a name without extension, network failure to the media endpoint, or HTTP >= 300 from the upload API (401 invalid token, 413 too large, 415 unsupported kind).

Common situations: Token expiry, files above MAX's upload limit, audio/image files whose MIME hint picks an upload kind the API rejects, flaky network to the media host.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


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