{"record":{"id":"8145dc6a3f03e04a","repo":"juicedata/juicefs","slug":"uploadpart-s","errorCode":null,"errorMessage":"UploadPart: %s","messagePattern":"UploadPart: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/object/ufile.go","lineNumber":296,"sourceCode":"\t}\n\tvar out ufileCreateMultipartUploadResult\n\tif err := u.parseResp(resp, &out); err != nil {\n\t\treturn nil, err\n\t}\n\treturn &MultipartUpload{UploadID: out.UploadId, MinPartSize: int64(out.BlkSize), MaxCount: 1000000}, nil\n}\n\nfunc (u *ufile) UploadPart(ctx context.Context, key string, uploadID string, num int, data []byte) (*Part, error) {\n\t// UFile require the PartNumber to start from 0 (continuous)\n\tnum--\n\tpath := fmt.Sprintf(\"%s?uploadId=%s&partNumber=%d\", key, uploadID, num)\n\tresp, err := u.request(ctx, \"PUT\", path, bytes.NewReader(data), nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer cleanup(resp)\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"UploadPart: %s\", parseError(resp).Error())\n\t}\n\tetags := resp.Header[\"Etag\"]\n\tif len(etags) < 1 {\n\t\treturn nil, errors.New(\"No ETag\")\n\t}\n\treturn &Part{Num: num, Size: len(data), ETag: strings.Trim(etags[0], \"\\\"\")}, nil\n}\n\nfunc (u *ufile) AbortUpload(ctx context.Context, key string, uploadID string) {\n\t_, _ = u.request(ctx, \"DELETE\", key+\"?uploads=\"+uploadID, nil, nil)\n}\n\nfunc (u *ufile) CompleteUpload(ctx context.Context, key string, uploadID string, parts []*Part) error {\n\tetags := make([]string, len(parts))\n\tfor i, p := range parts {\n\t\tetags[i] = p.ETag\n\t}\n\tresp, err := u.request(ctx, \"POST\", key+\"?uploadId=\"+uploadID, bytes.NewReader([]byte(strings.Join(etags, \",\"))), nil)","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/object/ufile.go#L278-L314","documentation":"Documentation placeholder for ufile UploadPart errors: the PUT request uploading one multipart part to UFile failed; UFile additionally requires part numbers to start from zero and be continuous, which the client adjusts for before this request.","triggerScenarios":"PUT of a part to UFile fails: signature error, part size below minimum (UFile requires parts >4MB except last), quota exceeded, network drop producing 5xx, or server omits the Etag header.","commonSituations":"Uploading large files where middle parts are too small; wrong secret key; UFile bucket storage class rejecting the upload; proxy stripping the Etag header.","solutions":["Check the wrapped parseError message for the actual UFile error code","Ensure non-final parts meet UFile's minimum part size (e.g. 4 MiB)","Verify access/secret keys and bucket binding","Retry the failed part; if ETag missing, check intermediaries/proxies stripping headers"],"exampleFix":"// before\nu.UploadPart(ctx, key, uploadID, num, 1<<20) // 1MB part\n// after\nu.UploadPart(ctx, key, uploadID, num, 8<<20) // >= 4MB part","handlingStrategy":"try-catch","validationCode":"func validPartSize(sz int) error { if sz < 4<<20 { return errors.New(\"part too small for UFile\") }; return nil }","typeGuard":null,"tryCatchPattern":"p, err := store.UploadPart(ctx, key, uploadID, num, data)\nif err != nil && strings.HasPrefix(err.Error(), \"UploadPart:\") {\n\t// backoff and retry this single part\n}","preventionTips":["Use parts >= 4 MiB (larger for big objects)","Retry individual parts with exponential backoff","Verify ETag presence; disable header-stripping proxies"],"tags":["ufile","multipart-upload","http","object-storage"],"backgroundTag":"http-error-response","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}