{"record":{"id":"50a91d45be6f2d18","repo":"sipeed/picoclaw","slug":"wecom-upload-init-returned-empty-upload-id","errorCode":null,"errorMessage":"wecom upload init returned empty upload_id","messagePattern":"wecom upload init returned empty upload_id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/channels/wecom/media.go","lineNumber":715,"sourceCode":"\t\tCmd:     wecomCmdUploadMediaInit,\n\t\tHeaders: wecomHeaders{ReqID: randomID(10)},\n\t\tBody: wecomUploadMediaInitBody{\n\t\t\tType:        kind,\n\t\t\tFilename:    filename,\n\t\t\tTotalSize:   size,\n\t\t\tTotalChunks: totalChunks,\n\t\t\tMD5:         hex.EncodeToString(sum[:]),\n\t\t},\n\t}, wecomUploadTimeout)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tinitResp, err := decodeWeComEnvelopeBody[wecomUploadMediaInitResponse](initEnv)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif strings.TrimSpace(initResp.UploadID) == \"\" {\n\t\treturn nil, fmt.Errorf(\"wecom upload init returned empty upload_id\")\n\t}\n\n\tfor idx, offset := 0, 0; offset < len(data); idx, offset = idx+1, offset+wecomUploadChunkMaxBytes {\n\t\tend := offset + wecomUploadChunkMaxBytes\n\t\tif end > len(data) {\n\t\t\tend = len(data)\n\t\t}\n\t\tsendErr := c.sendCommand(wecomCommand{\n\t\t\tCmd:     wecomCmdUploadMediaChunk,\n\t\t\tHeaders: wecomHeaders{ReqID: randomID(10)},\n\t\t\tBody: wecomUploadMediaChunkBody{\n\t\t\t\tUploadID:   initResp.UploadID,\n\t\t\t\tChunkIndex: idx,\n\t\t\t\tBase64Data: base64.StdEncoding.EncodeToString(data[offset:end]),\n\t\t\t},\n\t\t}, wecomUploadTimeout)\n\t\tif sendErr != nil {\n\t\t\treturn nil, sendErr","sourceCodeStart":697,"sourceCodeEnd":733,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/channels/wecom/media.go#L697-L733","documentation":"The WeCom upload protocol completed the upload/init handshake without error (the ack envelope decoded), but the response carried an empty or whitespace-only upload_id. Every subsequent chunk/finish command needs that upload_id, so the channel aborts immediately. This indicates a server-side or protocol-level anomaly rather than a client mistake.","triggerScenarios":"Calling uploadOutboundMedia (i.e. sending any WeCom message with media) when the WeCom gateway acknowledges wecomCmdUploadMediaInit but omits upload_id in the decoded wecomUploadMediaInitResponse — server glitch, gateway version mismatch, or a truncated/malformed ack body that still passed envelope decoding.","commonSituations":"Transient WeCom service disruption during a burst of uploads; the WeCom WebSocket gateway was upgraded and changed the init ack schema; a proxy/middlebox rewrote or truncated the response body; extremely rare in steady state.","solutions":["Retry the send after a short backoff — empty upload_id is usually transient","Inspect the raw init ack (enable debug logging of the wecom channel) to confirm whether upload_id is truly absent vs. nested under a different key after a schema change","If persistent, compare against the current WeCom upload protocol and update wecomUploadMediaInitResponse field tags","Fall back to sending text-only content so the user gets a reply while media uploads are failing (the channel already does this for upload failures)"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"null","typeGuard":"func isWecomEmptyUploadID(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"empty upload_id\")\n}","tryCatchPattern":"var lastErr error\nfor attempt := 0; attempt < 3; attempt++ {\n    if err := ch.Send(msg); err != nil {\n        if !isWecomEmptyUploadID(err) {\n            lastErr = err\n            break\n        }\n        time.Sleep(time.Duration(attempt+1) * 2 * time.Second)\n        lastErr = err\n        continue\n    }\n    lastErr = nil\n    break\n}","preventionTips":["Retry transient upload-protocol errors with backoff; each retry gets a fresh upload_id","Log the raw init ack when diagnosing repeated occurrences","Keep attachments small so the whole upload cycle is short and less exposed to session glitches"],"tags":["wecom","media","upload","protocol","server-error"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}