{"record":{"id":"049eb0260d38723d","repo":"AlistGo/alist","slug":"invalid-multipart-parts","errorCode":null,"errorMessage":"invalid multipart parts","messagePattern":"invalid multipart parts","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"drivers/wukong/driver.go","lineNumber":605,"sourceCode":"\t}\n\tif resp.Code != minUploadSubmitSuccess {\n\t\treturn fmt.Errorf(\"wukong upload to tos failed: code=%d message=%s\", resp.Code, resp.Message)\n\t}\n\tif resp.Data.Crc32 != \"\" && !strings.EqualFold(resp.Data.Crc32, crc32Hex) {\n\t\treturn fmt.Errorf(\"wukong upload to tos crc32 mismatch: local=%s remote=%s\", crc32Hex, resp.Data.Crc32)\n\t}\n\treturn nil\n}\n\nfunc (d *Wukong) uploadToTOSMultipart(ctx context.Context, host, storeURI, auth, storageUser string, tempFile model.File, size int64, up driver.UpdateProgress) error {\n\tuploadID, err := d.initMultipartUpload(ctx, host, storeURI, auth, storageUser)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttotalParts := int((size + multipartChunkSize - 1) / multipartChunkSize)\n\tif totalParts <= 0 {\n\t\treturn errors.New(\"invalid multipart parts\")\n\t}\n\tparts := make([]string, 0, totalParts)\n\tfor i := 0; i < totalParts; i++ {\n\t\tpartNumber := i + 1\n\t\toffset := int64(i) * multipartChunkSize\n\t\tpartSize := multipartChunkSize\n\t\tif remain := size - offset; remain < partSize {\n\t\t\tpartSize = remain\n\t\t}\n\t\tbuf := make([]byte, partSize)\n\t\tn, readErr := tempFile.ReadAt(buf, offset)\n\t\tif readErr != nil && readErr != io.EOF {\n\t\t\treturn readErr\n\t\t}\n\t\tbuf = buf[:n]\n\t\tcrc32Hex := fmt.Sprintf(\"%08x\", crc32.ChecksumIEEE(buf))\n\t\tremoteCRC32, err := d.uploadMultipartPart(ctx, host, storeURI, auth, storageUser, uploadID, partNumber, buf, crc32Hex)\n\t\tif err != nil {","sourceCodeStart":587,"sourceCodeEnd":623,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/wukong/driver.go#L587-L623","documentation":"Thrown by uploadToTOSMultipart when the computed part count is <= 0. totalParts = ceil(size / multipartChunkSize); the function is only called when size > multipartChunkSize, which forces totalParts >= 1, so in the current call graph this is a defensive guard against a non-positive size rather than a reachable condition. Seeing it means the function was invoked with size <= 0 (e.g. via refactoring or a direct call), or multipartChunkSize became <= 0/overflowed.","triggerScenarios":"Direct invocation of uploadToTOSMultipart with a zero or negative size; a future code path that calls it for small files; chunk-size constant accidentally changed to 0 or a negative value.","commonSituations":"Driver forks or refactors that bypass the size > multipartChunkSize branch; uploading an empty (0-byte) file through a modified Put() that skips the size check; unit tests calling the helper directly.","solutions":["Route uploads through Put()/uploadToTOS so the size > multipartChunkSize precondition holds","If calling the helper directly, verify size > multipartChunkSize first","For 0-byte files, ensure the single-shot (non-multipart) branch is taken"],"exampleFix":"// before\nerr := d.uploadToTOSMultipart(ctx, host, uri, auth, uid, tempFile, size, up)\n\n// after\nif size > multipartChunkSize {\n    err = d.uploadToTOSMultipart(ctx, host, uri, auth, uid, tempFile, size, up)\n} else {\n    err = d.uploadToTOSDirect(ctx, host, uri, auth, uid, tempFile, up)\n}","handlingStrategy":"validation","validationCode":"if size <= multipartChunkSize {\n    return fmt.Errorf(\"size %d does not require multipart upload\", size)\n}\n// now safe: totalParts = ceil(size/chunk) >= 1","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only call uploadToTOSMultipart when size > multipartChunkSize","Handle 0-byte files in the single-shot branch","Never modify multipartChunkSize to 0 or negative"],"tags":["wukong","driver","upload","multipart","defensive-guard"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}