juicedata/juicefs · error

Length mismatch: %v != %v

Error message

Length mismatch: %v != %v

What it means

wSlice.Finish(length) is the finalization call on a staging slice writer; it validates that the final size the caller declares equals the length tracked on the slice (s.length, i.e. what was actually written via Write/FlushTo). If they differ, the library refuses to finalize because committing would record a size inconsistent with the data written, and returns "Length mismatch: <tracked> != <given>".

Source

Thrown at pkg/chunk/cached_store.go:487

		panic(fmt.Sprintf("Invalid offset: %d < %d", offset, s.uploaded))
	}
	for i, block := range s.pages {
		start := i * s.store.conf.BlockSize
		end := start + s.store.conf.BlockSize
		if start >= s.uploaded && end <= offset {
			if block != nil {
				s.upload(i)
			}
			s.uploaded = end
		}
	}

	return nil
}

func (s *wSlice) Finish(length int) error {
	if s.length != length {
		return fmt.Errorf("Length mismatch: %v != %v", s.length, length)
	}

	n := (length-1)/s.store.conf.BlockSize + 1
	if err := s.FlushTo(n * s.store.conf.BlockSize); err != nil {
		return err
	}
	for i := 0; i < s.pendings; i++ {
		if err := <-s.errors; err != nil {
			s.uploadError = err
			return err
		}
	}
	return nil
}

func (s *wSlice) Abort() {
	for i := range s.pages {
		for _, b := range s.pages[i] {

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Pass the actual number of bytes written to Finish — track the return value of Write calls instead of assuming a size.
  2. Check for earlier swallowed write errors; a short write before Finish means the tracked length is legitimately smaller.
  3. If the intended size is known up front, write exactly that many bytes (or pad/truncate) before calling Finish.
  4. Audit the calling code path for a stale variable holding an old length after the content changed.

Example fix

// before
n := computeExpectedSize(path)
err := w.Finish(n) // assumes size
// after
written := 0
for _, chunk := range chunks {
    k, e := w.Write(chunk)
    if e != nil { return e }
    written += k
}
err := w.Finish(written)
Defensive patterns

Strategy: validation

Validate before calling

if trackedBytes != declaredLength {
    return fmt.Errorf("refusing Finish: wrote %d bytes but Finish(%d) requested", trackedBytes, declaredLength)
}
err := w.Finish(declaredLength)

Try / catch

if err != nil && strings.HasPrefix(err.Error(), "Length mismatch:") {
    parts := strings.Split(err.Error(), " ")
    tracked, _ := strconv.Atoi(parts[2])
    return w.Finish(tracked) // finalize with the actual written size
}

Prevention

When it happens

Trigger: Calling Finish(n) on a wSlice whose writes produced a different byte count than n — e.g. a caller that pre-computed the file size but wrote fewer/more bytes, or that calls Finish after a partial Write failed silently.

Common situations: Applications that write via the JuiceFS SDK/fs layer and pass a stale or assumed size to Finish; a truncated or failed write earlier in the pipeline so tracked length is short; off-by-one or unit mistakes (bytes vs. records) when computing the final length.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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