chenhg5/cc-connect · error
decode upload finish response: %w
Error message
decode upload finish response: %w
What it means
The aibot_upload_media_finish ack arrived but its body could not be parsed as JSON containing a 'media_id' field. This indicates the server returned an unexpected body — often an error payload or a protocol version mismatch rather than the expected {"media_id":"..."} shape.
Source
Thrown at platform/wecom/websocket_outbound_media.go:117
}
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},
"body": map[string]any{
"chatid": chatID,
"msgtype": mediaType,
mediaType: map[string]string{
"media_id": mediaID,
},View on GitHub (pinned to 4000b2338a)
Solutions
- Log finishResp.Body verbatim to see what the server actually returned
- Check for an embedded error code/message in the body and surface it instead of the raw unmarshal error
- Update the finishBody struct to match the current WeCom AI Bot API response schema
- Confirm you are on a supported WeCom AI Bot protocol version
Example fix
// before
if err := json.Unmarshal(finishResp.Body, &finishBody); err != nil {
return "", fmt.Errorf("decode upload finish response: %w", err)
}
// after
if err := json.Unmarshal(finishResp.Body, &finishBody); err != nil {
return "", fmt.Errorf("decode upload finish response %s: %w", string(finishResp.Body), err)
} Defensive patterns
Strategy: try-catch
Type guard
func isValidFinishBody(b []byte) bool {
var probe struct {
MediaID string `json:"media_id"`
}
return json.Unmarshal(b, &probe) == nil
} Try / catch
mediaID, err := p.SendFile(ctx, rc, file)
if err != nil && strings.Contains(err.Error(), "decode upload finish response") {
log.Error("unexpected finish ack", "err", err) // inspect server body in logs
} Prevention
- Log raw response bodies for protocol errors
- Pin/track the WeCom AI Bot API version you integrate against
- Add a schema smoke test for the finish response shape
When it happens
Trigger: Called from SendImage/SendFile via uploadWSMedia when json.Unmarshal(finishResp.Body, &finishBody) fails after a successful finish ack.
Common situations: WeCom API version changed the finish response schema; the server returned an error JSON (different fields) with a 200-style ack; a gateway/proxy substituted an HTML or text error body.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- decode %s response: %w
- session.create decode: %w
- get_bot_qrcode json: %w
- get_qrcode_status json: %w
- invalid json response: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/39aecfcd3eb1f50d.
Report an issue: GitHub.