{"record":{"id":"bb93e81b163d62e4","repo":"chenhg5/cc-connect","slug":"close-multipart-writer-w","errorCode":null,"errorMessage":"close multipart writer: %w","messagePattern":"close multipart writer: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/dingtalk/dingtalk.go","lineNumber":1360,"sourceCode":"\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() }()\n\n\trespBody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"read upload response: %w\", err)","sourceCodeStart":1342,"sourceCodeEnd":1378,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/dingtalk/dingtalk.go#L1342-L1378","documentation":"multipart.Writer.Close() failed when finalizing the upload body for the DingTalk media API. Close flushes the closing boundary; failure here means the multipart body is incomplete and the request must not be sent.","triggerScenarios":"writer.Close() returns an error in uploadMedia after all parts were written — typically an underlying buffer write failure or calling Close after the writer was already closed.","commonSituations":"Double-Close after a refactor; memory pressure on huge media bodies; custom io.Writer sink that errors on flush.","solutions":["Ensure Close is called exactly once, after all parts are written.","If Close fails, abandon the body and rebuild it — a half-closed multipart body yields server-side parse errors.","For large media, write to a temp file sink instead of an in-memory buffer to avoid allocation failures."],"exampleFix":"// before\ndefer writer.Close()\n...\nreq, _ := http.NewRequestWithContext(ctx, \"POST\", uploadURL, body) // may race Close\n// after\nif err := writer.Close(); err != nil { return \"\", fmt.Errorf(\"close multipart writer: %w\", err) }\nreq, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadURL, body)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := writer.Close(); err != nil {\n    return \"\", fmt.Errorf(\"close multipart writer: %w\", err) // do NOT send the request\n}","preventionTips":["Call Close exactly once, after all parts, and check its error before building the request.","Never defer Close when the result gates whether the request is sent.","Rebuild the body from scratch if Close fails."],"tags":["dingtalk","multipart","upload"],"backgroundTag":"multipart-form-error","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"}