{"record":{"id":"a8558924dc30071e","repo":"chenhg5/cc-connect","slug":"empty-media-id-in-upload-response-s","errorCode":null,"errorMessage":"empty media_id in upload response: %s","messagePattern":"empty media_id in upload response: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/dingtalk/dingtalk.go","lineNumber":1402,"sourceCode":"\n\tslog.Debug(\"dingtalk: media upload response\", \"status\", resp.StatusCode, \"body\", string(respBody))\n\n\tvar uploadResp struct {\n\t\tErrCode int    `json:\"errcode\"`\n\t\tErrMsg  string `json:\"errmsg\"`\n\t\tMediaID string `json:\"media_id\"`\n\t\tType    string `json:\"type\"`\n\t}\n\tif err := json.Unmarshal(respBody, &uploadResp); err != nil {\n\t\treturn \"\", fmt.Errorf(\"decode upload response: %w, body: %s\", err, respBody)\n\t}\n\n\tif uploadResp.ErrCode != 0 {\n\t\treturn \"\", fmt.Errorf(\"upload API error %d: %s\", uploadResp.ErrCode, uploadResp.ErrMsg)\n\t}\n\n\tif uploadResp.MediaID == \"\" {\n\t\treturn \"\", fmt.Errorf(\"empty media_id in upload response: %s\", respBody)\n\t}\n\n\tslog.Debug(\"dingtalk: media uploaded successfully\", \"media_id\", uploadResp.MediaID, \"type\", mediaType, \"size\", len(data))\n\treturn uploadResp.MediaID, nil\n}\n\nfunc (p *Platform) Stop() error {\n\tif p.streamCtxCancel != nil {\n\t\tp.streamCtxCancel()\n\t}\n\tif p.streamClient != nil {\n\t\tp.streamClient.Close()\n\t}\n\treturn nil\n}\n\n// formatReplyContent prepends quoted text to the message content when the user\n// replies to / quotes a previous message. richText is parsed from the raw JSON","sourceCodeStart":1384,"sourceCodeEnd":1420,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/dingtalk/dingtalk.go#L1384-L1420","documentation":"The media upload API answered HTTP 200 with errcode 0 (success), yet the media_id field in the JSON response is empty. Since a valid media_id is required to send the media later, the platform treats this as a failed upload and returns the raw response body for inspection. This guards against silently succeeding with an unusable media id.","triggerScenarios":"DingTalk returns a success envelope whose media_id key is absent, null, or an empty string — e.g. a changed/renamed response field in some API version, a success response for a type the account cannot actually store, or a partially-finished upload acknowledged early.","commonSituations":"DingTalk API behavior change or regional endpoint difference; responses proxied/rewritten by middleware stripping fields; uploading with an app type that acknowledges but does not persist the media; testing against a mocked/stubbed DingTalk API.","solutions":["Inspect the body in the error message — check what keys the response actually contains (media_id vs mediaId, nested payload, etc.).","Confirm you are calling the current official media/upload endpoint for your app type (enterprise internal app vs. custom robot).","Check the DingTalk Open Platform changelog for response schema changes for media upload.","Retest with a small, well-formed image upload to rule out type-specific quirks.","If using a mock/proxy for testing, ensure it returns a non-empty media_id field."],"exampleFix":"// caller-side guard\nmediaID, err := platform.UploadMedia(ctx, data, \"image\")\nif err != nil {\n    if strings.Contains(err.Error(), \"empty media_id\") {\n        slog.Warn(\"dingtalk upload returned success but no media_id; check API version/response keys\")\n    }\n    return err\n}","handlingStrategy":"validation","validationCode":"// caller-side sanity check after a successful upload\nmediaID, err := uploadMedia(ctx, data, mediaType)\nif err == nil && mediaID == \"\" {\n    return fmt.Errorf(\"upload returned empty media_id\")\n}","typeGuard":null,"tryCatchPattern":"mediaID, err := uploadMedia(ctx, data, mediaType)\nif err != nil {\n    if strings.Contains(err.Error(), \"empty media_id\") {\n        // treat as failure; log raw response for API-version debugging\n        slog.Error(\"dingtalk upload succeeded without media_id; check API version\", \"detail\", err.Error())\n    }\n    return err\n}","preventionTips":["Pin to documented DingTalk API endpoints and review changelogs for response schema changes.","Always assert non-empty media_id before using it to send media.","Beware of proxies/mocks that strip or rename response fields.","Test uploads with a minimal image to catch schema regressions early."],"tags":["api","upload","response","dingtalk"],"backgroundTag":"unexpected-response-shape","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"}