juicedata/juicefs · error

src read: %s

Error message

src read: %s

What it means

io.ReadFull on the SOURCE range reader returned fewer bytes than requested (usually io.ErrUnexpectedEOF) or another read error. The source object delivered less data than its reported size/range, so comparison cannot proceed.

Source

Thrown at pkg/sync/sync.go:576

	in2, err := dst.Get(ctx, key, offset, length)
	if err != nil {
		return fmt.Errorf("dest get: %s", err)
	}
	defer in2.Close()

	buf := bufPool.Get().(*[]byte)
	defer bufPool.Put(buf)
	buf2 := bufPool.Get().(*[]byte)
	defer bufPool.Put(buf2)
	for left := int(length); left > 0; left -= bufferSize {
		bs := bufferSize
		if left < bufferSize {
			bs = left
		}
		*buf = (*buf)[:bs]
		*buf2 = (*buf2)[:bs]
		if _, err = io.ReadFull(in, *buf); err != nil {
			return fmt.Errorf("src read: %s", err)
		}
		if _, err = io.ReadFull(in2, *buf2); err != nil {
			return fmt.Errorf("dest read: %s", err)
		}
		if !bytes.Equal(*buf, *buf2) {
			return fmt.Errorf("bytes not equal")
		}
	}
	return nil
}

func compObjBinary(src, dst object.ObjectStorage, key string, abort chan struct{}, obj object.Object) (bool, error) {
	var err error
	if obj.Size() < maxBlock {
		err = compObjPartBinary(src, dst, key, abort, 0, obj.Size())
	} else {
		n := int((obj.Size()-1)/defaultPartSize) + 1
		errs := make(chan error, n)

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Retry the comparison; the wrapped io error tells whether it was UnexpectedEOF (truncation) or a connection error.
  2. Exclude concurrently-written keys from the sync or re-copy the object after the writer finishes.
  3. Verify object size on src matches what listing reported; if not, re-sync the object.
  4. Check for proxy/firewall idle-timeout killing long reads; reduce part size.
Defensive patterns

Strategy: retry

Validate before calling

// verify reported size before reading
info, err := src.Head(ctx, key)
if err != nil || info.Size() < offset+length {
	return fmt.Errorf("source size changed or too small for %s", key)
}

Try / catch

if err := comparePart(...); err != nil {
	if strings.Contains(err.Error(), "src read: unexpected EOF") {
		return retryCompareWithBackoff(3)
	}
	return err
}

Prevention

When it happens

Trigger: Object size changed between HEAD/Listing and the ranged GET; truncated upload on the source; connection dropped mid-read; backend returning short reads.

Common situations: Syncing live buckets where a writer is uploading/overwriting the object concurrently; unstable networks; providers with eventual-consistency quirks.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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