juicedata/juicefs · error

begin upload

Error message

begin upload %s: %w

What it means

storjClient.putOnce starts a multipart-style upload via project.UploadObject; failure to begin the upload is wrapped as 'begin upload <key>' with %w preserving the Storj cause. This happens before any data is transferred, so it indicates the upload could not be initiated at all.

Solutions

  1. Verify the bucket still exists and the access grant is valid; recreate bucket or regenerate the access grant.
  2. Check the object key is valid (UTF-8, no NUL bytes) before calling Put.
  3. Check network connectivity to the Storj satellite and retry; upstream the wrapped error (%w) for the precise cause.
Defensive patterns

Strategy: retry

Validate before calling

_, err := project.ListBuckets(ctx, &uplink.ListBucketsOptions{})
if err != nil { return fmt.Errorf("storj project unreachable or bad grant: %v", err) }

Try / catch

err := storjBackoff(ctx, func() error { return client.Put(ctx, key, in) })
if err != nil && strings.Contains(err.Error(), "begin upload") {
    // check grant validity/bucket existence before next retry
    return err
}

Prevention

When it happens

Trigger: project.UploadObject returns an error: bucket doesn't exist, invalid/revoked access grant, key invalid for Storj (e.g. invalid UTF-8 or disallowed), context cancelled, or satellite/network unreachable.

Common situations: Writing to a bucket that was deleted after mount; expired Storj access grant mid-session; uploading keys with characters Storj rejects; network partition to the satellite.

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/bf338be6b137d27c. Report an issue: GitHub.

Appendix: source

Thrown at pkg/object/storj.go:164

	if !seekable {
		return s.putOnce(ctx, key, in)
	}
	startPos, err := rs.Seek(0, io.SeekCurrent)
	if err != nil {
		return fmt.Errorf("capture read position %s: %w", key, err)
	}
	return storjBackoff(ctx, func() error {
		if _, err := rs.Seek(startPos, io.SeekStart); err != nil {
			return err
		}
		return s.putOnce(ctx, key, rs)
	})
}

func (s *storjClient) putOnce(ctx context.Context, key string, in io.Reader) error {
	upload, err := s.project.UploadObject(ctx, s.bucket, key, nil)
	if err != nil {
		return fmt.Errorf("begin upload %s: %w", key, err)
	}
	if _, err = io.Copy(upload, in); err != nil {
		_ = upload.Abort()
		return fmt.Errorf("upload %s: %w", key, err)
	}
	if err = upload.Commit(); err != nil {
		_ = upload.Abort()
		return fmt.Errorf("commit upload %s: %w", key, err)
	}
	return nil
}

func (s *storjClient) Copy(ctx context.Context, dst, src string) error {
	return storjBackoff(ctx, func() error {
		_, err := s.project.CopyObject(ctx, s.bucket, src, s.bucket, dst, nil)
		return err
	})
}

View on GitHub (pinned to c9a67b23e8)