{"record":{"id":"6935b5ba233572ea","repo":"chenhg5/cc-connect","slug":"write-media-data-w","errorCode":null,"errorMessage":"write media data: %w","messagePattern":"write media data: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/dingtalk/dingtalk.go","lineNumber":1356,"sourceCode":"// mediaType should be \"voice\" or \"image\".\nfunc (p *Platform) uploadMedia(ctx context.Context, data []byte, fileName, mediaType string) (string, error) {\n\ttoken, err := p.getAccessToken()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"get access token: %w\", err)\n\t}\n\n\tuploadURL := fmt.Sprintf(\"https://oapi.dingtalk.com/media/upload?access_token=%s&type=%s\", token, mediaType)\n\n\tbody := bytes.NewBuffer(nil)\n\twriter := multipart.NewWriter(body)\n\n\tpart, err := writer.CreateFormFile(\"media\", fileName)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"create form file: %w\", err)\n\t}\n\n\tif _, err := part.Write(data); err != nil {\n\t\treturn \"\", fmt.Errorf(\"write media data: %w\", err)\n\t}\n\n\tif err := writer.Close(); err != nil {\n\t\treturn \"\", fmt.Errorf(\"close multipart writer: %w\", err)\n\t}\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadURL, body)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"create upload request: %w\", err)\n\t}\n\n\treq.Header.Set(\"Content-Type\", writer.FormDataContentType())\n\n\tresp, err := p.httpClient.Do(req)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"upload request: %w\", err)\n\t}\n\tdefer func() { _ = resp.Body.Close() }()","sourceCodeStart":1338,"sourceCodeEnd":1374,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/dingtalk/dingtalk.go#L1338-L1374","documentation":"Writing the raw media bytes into the multipart form field failed while assembling the upload body. Since the sink is an in-memory bytes.Buffer, this only fires on buffer write errors (e.g. allocation failure) or an internal writer-state problem, but it guards against sending a truncated media payload.","triggerScenarios":"part.Write(data) returns n < len(data) or an error inside uploadMedia while writing the file content for the DingTalk media/upload request.","commonSituations":"Very large audio blobs causing memory pressure/OOM on small hosts; concurrent mutation of the bytes.Buffer; passing a nil or already-consumed data slice after upstream compression failed silently.","solutions":["Check available memory if media files are large; compress before upload (the WAV→MP3 path already reduces size ~10:1).","Ensure data is the complete output of upload/compression and not an empty/truncated slice.","Build the multipart body once per upload in a single goroutine; never share buffers across requests."],"exampleFix":"// before\naudio, _, err := p.compressAudio(ctx, raw, \"wav\")\n_ = err\nmediaID, err := p.uploadMedia(ctx, audio, ...) // audio may be nil\n// after\nif err != nil || len(audio) == 0 { return fmt.Errorf(\"compress audio: %w\", err) }","handlingStrategy":"validation","validationCode":"if len(data) == 0 { return errors.New(\"empty media payload\") }\nif len(data) > maxMediaSize { return fmt.Errorf(\"media too large: %d bytes\", len(data)) }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check the payload is complete and non-empty before upload.","Compress large audio (WAV→MP3) to shrink the in-memory buffer.","Guard buffer/memory usage for large media; consider a file-backed sink."],"tags":["dingtalk","multipart","io","upload"],"backgroundTag":"file-write-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}