{"record":{"id":"6df817218022f646","repo":"chenhg5/cc-connect","slug":"empty-media-data","errorCode":null,"errorMessage":"empty media data","messagePattern":"empty media data","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/wecom/websocket_outbound_media.go","lineNumber":47,"sourceCode":"\t}\n\tif len(img.Data) == 0 {\n\t\treturn fmt.Errorf(\"wecom-ws: image data is empty\")\n\t}\n\n\tmediaID, err := p.uploadWSMedia(ctx, \"image\", wsImageFileName(img), img.Data)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"wecom-ws: send image: %w\", err)\n\t}\n\tif err := p.sendWSMediaMessage(ctx, rc.chatID, \"image\", mediaID); err != nil {\n\t\treturn fmt.Errorf(\"wecom-ws: send image: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (p *WSPlatform) uploadWSMedia(ctx context.Context, mediaType, filename string, data []byte) (string, error) {\n\ttotalChunks := (len(data) + wecomWSUploadChunkSize - 1) / wecomWSUploadChunkSize\n\tif totalChunks == 0 {\n\t\treturn \"\", fmt.Errorf(\"empty media data\")\n\t}\n\tif totalChunks > wecomWSUploadMaxChunks {\n\t\treturn \"\", fmt.Errorf(\"media too large: %d chunks exceeds maximum %d\", totalChunks, wecomWSUploadMaxChunks)\n\t}\n\n\tsum := md5.Sum(data)\n\tinitReqID := p.generateReqID(\"aibot_upload_media_init\")\n\tinitFrame := map[string]any{\n\t\t\"cmd\":     \"aibot_upload_media_init\",\n\t\t\"headers\": map[string]string{\"req_id\": initReqID},\n\t\t\"body\": map[string]any{\n\t\t\t\"type\":         mediaType,\n\t\t\t\"filename\":     filename,\n\t\t\t\"total_size\":   len(data),\n\t\t\t\"total_chunks\": totalChunks,\n\t\t\t\"md5\":          hex.EncodeToString(sum[:]),\n\t\t},\n\t}","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/wecom/websocket_outbound_media.go#L29-L65","documentation":"uploadWSMedia validates the media payload before starting a chunked upload to WeCom (WeChat Work) over the WebSocket transport. It computes totalChunks = ceil(len(data)/wecomWSUploadChunkSize); when the caller passes a zero-length byte slice there are no chunks to upload, so it refuses to initiate the aibot_upload_media_init handshake and returns this error instead of sending a doomed request. It exists to fail fast with a clear message rather than produce a confusing server-side failure.","triggerScenarios":"Calling WSPlatform.SendImage or SendFile (both call uploadWSMedia) with an empty data slice: e.g. os.ReadFile returning a 0-byte file, an HTTP download that yielded no bytes, or a nil/empty []byte passed programmatically.","commonSituations":"Reading an image/file from disk that is unexpectedly 0 bytes (truncated download, failed export, race where the writer hasn't flushed yet); a media-producing pipeline that swallows an upstream error and returns nil bytes; tests constructing SendImage calls without fixture data.","solutions":["Check len(data) > 0 (or that the file size is non-zero) before calling SendImage/SendFile and surface a clearer upstream error.","If the bytes come from a file, verify the file exists and is non-empty (os.Stat size > 0) and re-generate or re-download it if truncated.","If the bytes come from another function, fix that function to return an error instead of empty bytes on failure, then propagate it.","For unavoidable empties, skip the send (reply with a text message) rather than attempting media upload."],"exampleFix":"// before\nif err := p.SendImage(chatID, data, \"photo.png\"); err != nil { ... } // panics later with \"empty media data\"\n\n// after\nif len(data) == 0 {\n    return fmt.Errorf(\"wecom: image data is empty, file may be corrupt or missing\")\n}\nif err := p.SendImage(chatID, data, \"photo.png\"); err != nil { ... }","handlingStrategy":"validation","validationCode":"func canUpload(data []byte) error {\n    if len(data) == 0 {\n        return errors.New(\"media data is empty; source file may be missing or corrupt\")\n    }\n    return nil\n}\n// call before SendImage/SendFile: if err := canUpload(data); err != nil { return err }","typeGuard":"func hasMediaData(data []byte) bool { return len(data) > 0 }","tryCatchPattern":"var err *EmptyMediaError\nif errors.As(err2, &err) {\n    // regenerate or skip the media item, log with context\n}","preventionTips":["Always os.Stat the source file and check Size() > 0 before reading and sending.","Make every media-producing function return (data, error) and treat nil data + nil error as a bug.","Add a unit test asserting SendImage rejects empty data with a clear message.","Validate media immediately after generation (download/encode), not at send time."],"tags":["wecom","media-upload","validation","empty-payload"],"backgroundTag":"empty-required-field","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}