juicedata/juicefs · error

failed to complete multipart upload: %v

Error message

failed to complete multipart upload: %v

What it means

Returned when blob.CompleteUpload fails after all parts were uploaded in the objbench 'multipart upload' case. CompleteUpload sends the part list (ETags) to finalize the object; failures mean the backend refused to commit — invalid or aborted upload ID, missing/incomplete parts, ETag mismatch, or backend error. The object remains uncommitted (and typically invisible) when this fires.

Source

Thrown at cmd/objbench.go:1076

			if err != nil {
				return err
			}
			// overwrite the first part
			firstPartContent := append(seed, seed...)
			if parts[0], err = blob.UploadPart(ctx, key, upload.UploadID, 1, firstPartContent); err != nil {
				return fmt.Errorf("multipart upload error: %v", err)
			}
			content[0] = firstPartContent

			// overwrite the last part
			lastPartContent := []byte("hello")
			if parts[total-1], err = blob.UploadPart(ctx, key, upload.UploadID, total, lastPartContent); err != nil {
				return fmt.Errorf("multipart upload error: %v", err)
			}
			content[total-1] = lastPartContent

			if err = blob.CompleteUpload(ctx, key, upload.UploadID, parts); err != nil {
				return fmt.Errorf("failed to complete multipart upload: %v", err)
			}
			r, err := blob.Get(ctx, key, 0, -1)
			if err != nil {
				return fmt.Errorf("failed to get multipart upload file: %v", err)
			}
			cnt, err := io.ReadAll(r)
			if err != nil {
				return fmt.Errorf("failed to get multipart upload file: %v", err)
			}
			if !bytes.Equal(cnt, bytes.Join(content, nil)) {
				return fmt.Errorf("the content of the multipart upload file is incorrect")
			}
			return nil
		}
		return utils.ErrNotSUP
	})

	funFSCase("change owner/group", func() error {

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Check the wrapped error for S3 codes like InvalidPart, InvalidPartOrder, NoSuchUpload; fix part ordering (ascending part numbers) before completing.
  2. Verify all parts in the list were uploaded successfully with valid ETags from UploadPart responses.
  3. Re-run with a fresh CreateMultipartUpload session if NoSuchUpload/expiry was reported.
  4. Confirm the credentials can perform CompleteMultipartUpload on the bucket.

Example fix

// before
if err = blob.CompleteUpload(ctx, key, upload.UploadID, parts); err != nil {
	return fmt.Errorf("failed to complete multipart upload: %v", err)
}
// after
if err = blob.CompleteUpload(ctx, key, upload.UploadID, parts); err != nil {
	if errors.Is(err, utils.ErrNotSUP) {
		return utils.ErrNotSUP
	}
	return fmt.Errorf("failed to complete multipart upload (uploadID=%s): %w", upload.UploadID, err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before CompleteUpload, verify the part list is complete and ordered
for i, p := range parts {
	if p == nil || p.ETag == "" {
		return fmt.Errorf("part %d missing ETag", i+1)
	}
}

Try / catch

if err = blob.CompleteUpload(ctx, key, upload.UploadID, parts); err != nil {
	if errors.Is(err, utils.ErrNotSUP) {
		return utils.ErrNotSUP
	}
	return fmt.Errorf("failed to complete multipart upload: %w", err)
}

Prevention

When it happens

Trigger: CompleteUpload called with parts whose ETags/numbers don't match what the backend recorded (e.g. a part overwritten with different content than listed), the upload session was aborted or expired, or the backend returned 4xx/5xx on the complete request.

Common situations: S3 'InvalidPart'/'InvalidPartOrder' due to out-of-order part list, another client/abort removed the upload, part size below the store's minimum, or quota/permission errors on finalize.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/a5f31da4404798ee. Report an issue: GitHub.