juicedata/juicefs · error

create multipart upload failed

Error message

create multipart upload failed: %s

What it means

objbench's multipart-upload test first checks CompleteUpload returns utils.ErrNotSUP (backend uses built-in multipart). If not, it starts a real multipart upload via CreateMultipartUpload and wraps failures with this message — meaning the backend refused to initiate a multipart upload.

Solutions

  1. Read the wrapped backend error for the root cause
  2. If the backend lacks multipart support, its driver should return utils.ErrNotSUP from CreateMultipartUpload
  3. Grant multipart-upload permissions (e.g. s3:CreateMultipartUpload) on the bucket
  4. Test with a backend known to support multipart

Example fix

// before
upload, err := blob.CreateMultipartUpload(ctx, key)
if err != nil { return fmt.Errorf("create multipart upload failed: %s", err) }
// after (driver without multipart support)
func (s *store) CreateMultipartUpload(ctx context.Context, key string) (*object.MultipartUpload, error) {
    return nil, utils.ErrNotSUP
}
Defensive patterns

Strategy: fallback

Validate before calling

if _, err := blob.CreateMultipartUpload(ctx, "probe"); err != nil {
    // backend lacks multipart; use single-put path
}
_ = blob.AbortUpload(ctx, "probe", id) // cleanup if created

Try / catch

upload, err := blob.CreateMultipartUpload(ctx, key)
if err != nil {
    if errors.Is(err, utils.ErrNotSUP) { /* fall back to Put */ }
    return fmt.Errorf("create multipart upload failed: %s", err)
}

Prevention

When it happens

Trigger: `blob.CreateMultipartUpload(ctx, "multi_test_file")` returns an error — backend doesn't implement MultipartUpload, lacks permission, or returns an API error.

Common situations: Stores without multipart support that don't properly return ErrNotSUP; missing s3:PutObject/Multipart permissions; restricted endpoints (e.g. some S3-compatible gateways).

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at cmd/objbench.go:1033

		// Copy `/` suffixed object
		defer blob.Delete(ctx, "slash_test_file/") //nolint:errcheck
		if err := blob.Put(ctx, "slash_test_file/", bytes.NewReader([]byte("1"))); err != nil {
			return fmt.Errorf("put `/` suffixed object failed: %s", err)
		}
		return nil
	})

	runCase("multipart upload", func(blob object.ObjectStorage) (err error) {
		defer func() {
			err = warning(err)
		}()

		key := "multi_test_file"
		if err = blob.CompleteUpload(ctx, key, "notExistsUploadId", []*object.Part{}); err != utils.ErrNotSUP {
			defer blob.Delete(ctx, key) //nolint:errcheck
			upload, err := blob.CreateMultipartUpload(ctx, key)
			if err != nil {
				return fmt.Errorf("create multipart upload failed: %s", err)
			}
			total := 3
			seed := make([]byte, upload.MinPartSize)
			utils.RandRead(seed)
			parts := make([]*object.Part, total)
			content := make([][]byte, total)
			for i := 0; i < total; i++ {
				content[i] = make([]byte, upload.MinPartSize)
				getMockData(seed, i, &content[i])
			}
			var eg errgroup.Group
			eg.SetLimit(4)
			for i := 1; i <= total; i++ {
				num := i
				eg.Go(func() error {
					var err error
					parts[num-1], err = blob.UploadPart(ctx, key, upload.UploadID, num, content[num-1])
					if err != nil {

View on GitHub (pinned to c9a67b23e8)