{"record":{"id":"16c583b426c41485","repo":"juicedata/juicefs","slug":"length-mismatch-v-v","errorCode":null,"errorMessage":"Length mismatch: %v != %v","messagePattern":"Length mismatch: (.+?) != (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/chunk/cached_store.go","lineNumber":487,"sourceCode":"\t\tpanic(fmt.Sprintf(\"Invalid offset: %d < %d\", offset, s.uploaded))\n\t}\n\tfor i, block := range s.pages {\n\t\tstart := i * s.store.conf.BlockSize\n\t\tend := start + s.store.conf.BlockSize\n\t\tif start >= s.uploaded && end <= offset {\n\t\t\tif block != nil {\n\t\t\t\ts.upload(i)\n\t\t\t}\n\t\t\ts.uploaded = end\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (s *wSlice) Finish(length int) error {\n\tif s.length != length {\n\t\treturn fmt.Errorf(\"Length mismatch: %v != %v\", s.length, length)\n\t}\n\n\tn := (length-1)/s.store.conf.BlockSize + 1\n\tif err := s.FlushTo(n * s.store.conf.BlockSize); err != nil {\n\t\treturn err\n\t}\n\tfor i := 0; i < s.pendings; i++ {\n\t\tif err := <-s.errors; err != nil {\n\t\t\ts.uploadError = err\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (s *wSlice) Abort() {\n\tfor i := range s.pages {\n\t\tfor _, b := range s.pages[i] {","sourceCodeStart":469,"sourceCodeEnd":505,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/chunk/cached_store.go#L469-L505","documentation":"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>\".","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass the actual number of bytes written to Finish — track the return value of Write calls instead of assuming a size.","Check for earlier swallowed write errors; a short write before Finish means the tracked length is legitimately smaller.","If the intended size is known up front, write exactly that many bytes (or pad/truncate) before calling Finish.","Audit the calling code path for a stale variable holding an old length after the content changed."],"exampleFix":"// before\nn := computeExpectedSize(path)\nerr := w.Finish(n) // assumes size\n// after\nwritten := 0\nfor _, chunk := range chunks {\n    k, e := w.Write(chunk)\n    if e != nil { return e }\n    written += k\n}\nerr := w.Finish(written)","handlingStrategy":"validation","validationCode":"if trackedBytes != declaredLength {\n    return fmt.Errorf(\"refusing Finish: wrote %d bytes but Finish(%d) requested\", trackedBytes, declaredLength)\n}\nerr := w.Finish(declaredLength)","typeGuard":null,"tryCatchPattern":"if err != nil && strings.HasPrefix(err.Error(), \"Length mismatch:\") {\n    parts := strings.Split(err.Error(), \" \")\n    tracked, _ := strconv.Atoi(parts[2])\n    return w.Finish(tracked) // finalize with the actual written size\n}","preventionTips":["Always derive the Finish argument from the cumulative Write return values, never from an assumed size.","Check every Write error before finalizing; partial writes change the tracked length.","When a fixed size is required, write exactly that many bytes (pad or truncate) first.","Add an assertion in wrappers that compares bytes-written to the expected size before Finish."],"tags":["write-path","length-validation","api-misuse","state-mismatch"],"backgroundTag":"invalid-argument-value","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}