chenhg5/cc-connect · error
upload finish: %w
Error message
upload finish: %w
What it means
After all chunks are sent, uploadWSMedia sends an 'aibot_upload_media_finish' frame and waits for the ack that carries the final media_id. This error wraps a failure of that finish round trip (timeout, closed socket, or server rejection of the finish command). Without a successful finish the uploaded chunks are discarded server-side and no media_id is produced.
Source
Thrown at platform/wecom/websocket_outbound_media.go:111
"base64_data": base64.StdEncoding.EncodeToString(data[start:end]),
},
}
if _, err := p.writeAndWaitFrameWithTimeout(ctx, chunkFrame, reqID, wsMediaAckTimeout); err != nil {
return "", fmt.Errorf("upload chunk %d: %w", i, err)
}
}
finishReqID := p.generateReqID("aibot_upload_media_finish")
finishFrame := map[string]any{
"cmd": "aibot_upload_media_finish",
"headers": map[string]string{"req_id": finishReqID},
"body": map[string]any{
"upload_id": initBody.UploadID,
},
}
finishResp, err := p.writeAndWaitFrameWithTimeout(ctx, finishFrame, finishReqID, wsMediaAckTimeout)
if err != nil {
return "", fmt.Errorf("upload finish: %w", err)
}
var finishBody struct {
MediaID string `json:"media_id"`
}
if err := json.Unmarshal(finishResp.Body, &finishBody); err != nil {
return "", fmt.Errorf("decode upload finish response: %w", err)
}
if finishBody.MediaID == "" {
return "", fmt.Errorf("upload finish: empty media_id")
}
return finishBody.MediaID, nil
}
func (p *WSPlatform) sendWSMediaMessage(ctx context.Context, chatID, mediaType, mediaID string) error {
reqID := p.generateReqID("aibot_send_msg")
frame := map[string]any{
"cmd": "aibot_send_msg",
"headers": map[string]string{"req_id": reqID},View on GitHub (pinned to 4000b2338a)
Solutions
- Inspect the wrapped cause; on timeout retry the entire upload (init → chunks → finish) with a fresh upload_id
- Verify the WS connection is still open and reconnect before retrying
- Increase wsMediaAckTimeout if finishes regularly time out on large media
- Check WeCom AI Bot API status/permissions if finish is consistently rejected
Defensive patterns
Strategy: retry
Validate before calling
if !p.IsConnected() {
if err := p.reconnect(ctx); err != nil {
return err
}
} Try / catch
mediaID, err := p.SendFile(ctx, rc, file)
if err != nil && strings.Contains(err.Error(), "upload finish") {
// whole upload is discarded; retry once end-to-end
return p.SendFile(ctx, rc, file)
} Prevention
- Treat finish failure as full-upload failure — never reuse the upload_id
- Reconnect the WS before retrying finish
- Alert on repeated finish timeouts (server-side or quota issue)
When it happens
Trigger: Called from SendImage/SendFile via uploadWSMedia when writeAndWaitFrameWithTimeout for the aibot_upload_media_finish frame returns an error.
Common situations: WeCom rejects the finish because a chunk failed validation server-side; the WS ack timed out (wsMediaAckTimeout) under load; connection dropped between last chunk and finish; upload_id no longer valid due to server-side session expiry.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
Related errors
- upload chunk %d: %w
- wecom-ws: ack timeout
- read register_ack: %w
- cloud_web: websocket disconnected
- max: upload audio: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/6854db39b39c6c9e.
Report an issue: GitHub.