juicedata/juicefs · error

part %d: %s

Error message

part %d: %s

What it means

doUploadPart wraps any failure of a single multipart part copy as 'part %d: %s' after logging 'Failed to copy data of %s part %d'. The inner error (network, abort, permission, size errors from src.Get/dst.UploadPart) is embedded; the caller aborts the whole multipart upload.

Source

Thrown at pkg/sync/sync.go:832

		if obj, ok := dst.(object.SupportUploadPartStream); ok {
			part, err = obj.UploadPartStream(key, uploadID, num+1, pr)
		}

		if errors.Is(err, utils.ErrNotSUP) {
			data := dynAlloc(int(size))
			defer dynFree(data)
			if _, err = io.ReadFull(pr, data); err != nil {
				return err
			}
			// PartNumber starts from 1
			part, err = dst.UploadPart(ctx, key, uploadID, num+1, data)
		}
		chksum = r.chksum
		return err
	})
	if err != nil {
		logger.Warnf("Failed to copy data of %s part %d: %s", key, num, err)
		return nil, 0, fmt.Errorf("part %d: %s", num, err)
	}
	logger.Debugf("Copied data of %s part %d in %s", key, num, time.Since(start))
	return part, chksum, nil
}

func choosePartSize(upload *object.MultipartUpload, size int64) int64 {
	partSize := int64(upload.MinPartSize)
	if partSize == 0 {
		partSize = defaultPartSize
	}
	if size > partSize*int64(upload.MaxCount) {
		partSize = size / int64(upload.MaxCount)
		partSize = ((partSize-1)>>20 + 1) << 20 // align to MB
	}
	return partSize
}

func doCopyRange(src, dst object.ObjectStorage, key string, off, size int64, upload *object.MultipartUpload, num int, abort chan struct{}, calChksum bool) (*object.Part, uint32, error) {

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Read the embedded inner error for the real cause (429/5xx -> retry; 404 NoSuchUpload -> restart the whole multipart upload).
  2. The multipart upload is aborted by the caller; simply re-running the sync restarts it cleanly.
  3. Lower --threads or increase part size to reduce throttling on big objects.
  4. Verify dst credentials include multipart:UploadPart/AbortMultipartUpload.
Defensive patterns

Strategy: retry

Validate before calling

// ensure dst supports multipart before large copies
if size > 5*1024*1024 {
	if _, err := dst.CreateMultipartUpload(ctx, probeKey); err != nil {
		return fmt.Errorf("multipart unsupported/denied on dst: %w", err)
	}
}

Try / catch

part, chksum, err := doUploadPart(...)
if err != nil {
	// caller already aborts the upload; classify for retry policy
	if isTransient(err) { // 429/5xx
		return retryRangeCopyWithBackoff()
	}
	return fmt.Errorf("part %d: %w", num, err)
}

Prevention

When it happens

Trigger: UploadPart to dst fails (throttling, expired upload ID, permission), src range read fails, or abort fires while uploading one part during doCopyRange's multipart copy.

Common situations: Large objects with many parts where one part hits a 429/503; multipart upload expired on the backend; credentials lacking multipart permissions; user cancellation mid-part.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


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