chenhg5/cc-connect · error
upload init: empty upload_id
Error message
upload init: empty upload_id
What it means
The aibot_upload_media_init ack decoded successfully as JSON, but the upload_id field is empty. The upload_id is required to reference the subsequent chunk uploads, so without it the chunked upload cannot proceed and uploadWSMedia aborts with this explicit error rather than sending chunks the server can't reassemble.
Source
Thrown at platform/wecom/websocket_outbound_media.go:77
"type": mediaType,
"filename": filename,
"total_size": len(data),
"total_chunks": totalChunks,
"md5": hex.EncodeToString(sum[:]),
},
}
initResp, err := p.writeAndWaitFrameWithTimeout(ctx, initFrame, initReqID, wsMediaAckTimeout)
if err != nil {
return "", fmt.Errorf("upload init: %w", err)
}
var initBody struct {
UploadID string `json:"upload_id"`
}
if err := json.Unmarshal(initResp.Body, &initBody); err != nil {
return "", fmt.Errorf("decode upload init response: %w", err)
}
if initBody.UploadID == "" {
return "", fmt.Errorf("upload init: empty upload_id")
}
for i := 0; i < totalChunks; i++ {
start := i * wecomWSUploadChunkSize
end := start + wecomWSUploadChunkSize
if end > len(data) {
end = len(data)
}
reqID := p.generateReqID("aibot_upload_media_chunk")
chunkFrame := map[string]any{
"cmd": "aibot_upload_media_chunk",
"headers": map[string]string{"req_id": reqID},
"body": map[string]any{
"upload_id": initBody.UploadID,
"chunk_index": i,
"base64_data": base64.StdEncoding.EncodeToString(data[start:end]),
},
}View on GitHub (pinned to 4000b2338a)
Solutions
- Log the full ack body to check for an embedded error code/message the server returned instead of an upload_id.
- Verify bot credentials/token are valid and not expired — rejections often arrive as JSON without upload_id.
- Check for a WeCom API schema change and update the initBody struct (e.g. nested field or renamed key).
- Confirm the mediaType passed by SendImage/SendFile is one the server accepts for this upload command.
Example fix
// before
if initBody.UploadID == "" {
return "", fmt.Errorf("upload init: empty upload_id")
}
// after
if initBody.UploadID == "" {
if initBody.ErrCode != 0 {
return "", fmt.Errorf("upload init rejected: errcode=%d errmsg=%s", initBody.ErrCode, initBody.ErrMsg)
}
return "", fmt.Errorf("upload init: empty upload_id (body=%q)", string(initResp.Body))
} Defensive patterns
Strategy: type-guard
Validate before calling
type initAck struct {
UploadID string `json:"upload_id"`
ErrCode int `json:"errcode"`
ErrMsg string `json:"errmsg"`
}
func ackHasUploadID(body []byte) bool {
var a initAck
if json.Unmarshal(body, &a) != nil {
return false
}
return a.ErrCode == 0 && a.UploadID != ""
} Type guard
func uploadIDFromAck(body []byte) (string, error) {
var a initAck
if err := json.Unmarshal(body, &a); err != nil {
return "", err
}
if a.ErrCode != 0 {
return "", fmt.Errorf("server error %d: %s", a.ErrCode, a.ErrMsg)
}
if a.UploadID == "" {
return "", fmt.Errorf("ack missing upload_id: %s", string(body))
}
return a.UploadID, nil
} Try / catch
uploadID, err := uploadIDFromAck(initResp.Body)
if err != nil {
slog.Warn("wecom upload init: no upload_id", "body", string(initResp.Body), "err", err)
return "", fmt.Errorf("upload init: %w", err)
} Prevention
- Treat a JSON ack without upload_id as a server error response, not just an empty field — surface errcode/errmsg.
- Refresh bot credentials before uploads; expired tokens commonly produce id-less acks.
- Keep a regression test with a captured rejected-ack fixture to detect WeCom schema changes.
- Verify the mediaType/name are acceptable to the server before initiating the upload.
When it happens
Trigger: SendImage/SendFile when the WeCom server acks aibot_upload_media_init with a body lacking upload_id (e.g. an error ack like {"errcode":...} that still parses as JSON, or a schema where the field was renamed) so initBody.UploadID ends up "".
Common situations: WeCom API version change renaming or nesting the upload_id field; server-side rejection (auth expired, quota, invalid media type) returned in a JSON body without upload_id; bot credentials lacking the upload permission; sending a media_type the server session doesn't accept.
Understand the failure class
Background: "empty response", "returned no data", "empty embeddings": what HTTP 200-with-empty-body errors mean across libraries — this error's family across 36 libraries.
Related errors
- wecom-ws: send image: %w
- upload init: %w
- decode upload init response: %w
- wecom-ws: ack timeout
- googlechat: upload: empty resourceName in response
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/32adadf19740e40b.
Report an issue: GitHub.