{"record":{"id":"5af2d23652e769c7","repo":"juicedata/juicefs","slug":"ks3-uploadpartcopy-returned-no-copypartresult-for","errorCode":null,"errorMessage":"ks3: UploadPartCopy returned no CopyPartResult for %s part %d","messagePattern":"ks3: UploadPartCopy returned no CopyPartResult for (.+?) part (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/object/ks3.go","lineNumber":316,"sourceCode":"\t\t},\n\t})\n\treturn err\n}\n\nfunc (s *ks3) UploadPartCopy(ctx context.Context, key string, uploadID string, num int, srcKey string, off, size int64) (*Part, error) {\n\tresp, err := s.s3.UploadPartCopyWithContext(ctx, &s3.UploadPartCopyInput{\n\t\tBucket:          aws.String(s.bucket),\n\t\tCopySource:      aws.String(s.bucket + \"/\" + srcKey),\n\t\tCopySourceRange: aws.String(fmt.Sprintf(\"bytes=%d-%d\", off, off+size-1)),\n\t\tKey:             aws.String(key),\n\t\tPartNumber:      aws.Long(int64(num)),\n\t\tUploadID:        aws.String(uploadID),\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif resp.CopyPartResult == nil {\n\t\treturn nil, fmt.Errorf(\"ks3: UploadPartCopy returned no CopyPartResult for %s part %d\", key, num)\n\t}\n\treturn &Part{Num: num, ETag: aws.ToString(resp.CopyPartResult.ETag)}, nil\n}\n\nfunc (s *ks3) AbortUpload(ctx context.Context, key string, uploadID string) {\n\tparams := &s3.AbortMultipartUploadInput{\n\t\tBucket:   &s.bucket,\n\t\tKey:      &key,\n\t\tUploadID: &uploadID,\n\t}\n\t_, _ = s.s3.AbortMultipartUploadWithContext(ctx, params)\n}\n\nfunc (s *ks3) CompleteUpload(ctx context.Context, key string, uploadID string, parts []*Part) error {\n\tvar s3Parts []*s3.CompletedPart\n\tfor i := range parts {\n\t\tn := new(int64)\n\t\t*n = int64(parts[i].Num)","sourceCodeStart":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/object/ks3.go#L298-L334","documentation":"ks3.UploadPartCopy performs a server-side copy for one part of a multipart upload and requires resp.CopyPartResult to be present, since the part's ETag lives there. A 200 response with a nil CopyPartResult is treated as a failed copy and surfaces as \"ks3: UploadPartCopy returned no CopyPartResult for %s part %d\". Without the ETag the part cannot be validated in CompleteMultipartUpload.","triggerScenarios":"UploadPartCopy called where KS3 returns success but with a nil CopyPartResult — source object missing/unreadable server-side with error swallowed, response XML missing CopyPartResult due to a proxy, or SDK deserialization mismatch on the CopyPartResult field.","commonSituations":"Copying through a proxy that strips response elements; source object deleted between validation and copy; KS3-compatible endpoint not fully implementing UploadPartCopy; SDK version mismatch with the KS3 response format.","solutions":["Verify the source key exists and is readable at copy time (retry the operation).","Inspect the raw response with SDK debug logging to see whether CopyPartResult XML was returned but not parsed; update the SDK if so.","Bypass UploadPartCopy by re-uploading the part data directly via UploadPart if the endpoint doesn't fully support copy.","If using a proxy/compatible gateway, test against the genuine KS3 endpoint to isolate the culprit."],"exampleFix":"// before\n_, err := s.UploadPartCopy(ctx, dstKey, uploadID, num, srcKey, 0, size)  // nil CopyPartResult from proxy\n// after\n// read source and upload directly if copy is unsupported\npart, err := s.UploadPart(ctx, dstKey, uploadID, num, data)","handlingStrategy":"try-catch","validationCode":"if src, err := storage.Head(ctx, srcKey); err != nil || src == nil {\n    return fmt.Errorf(\"source %s not available for UploadPartCopy\", srcKey)\n}","typeGuard":null,"tryCatchPattern":"part, err := storage.UploadPartCopy(ctx, dstKey, uploadID, num, srcKey, off, size)\nif err != nil {\n    if strings.Contains(err.Error(), \"no CopyPartResult\") {\n        // fall back to reading the source and uploading the part directly\n        return uploadPartDirect(ctx, dstKey, uploadID, num, srcKey, off, size)\n    }\n    return err\n}","preventionTips":["Confirm the source object exists immediately before copy.","Avoid proxies that rewrite/strip S3 response XML.","Fall back to direct UploadPart for endpoints lacking full UploadPartCopy support.","Keep the KS3 SDK updated to match the response format."],"tags":["ks3","multipart-upload","copy","object-storage"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}