{"record":{"id":"2533b2cdb27512bb","repo":"juicedata/juicefs","slug":"src-read-s","errorCode":null,"errorMessage":"src read: %s","messagePattern":"src read: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/sync/sync.go","lineNumber":576,"sourceCode":"\tin2, err := dst.Get(ctx, key, offset, length)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"dest get: %s\", err)\n\t}\n\tdefer in2.Close()\n\n\tbuf := bufPool.Get().(*[]byte)\n\tdefer bufPool.Put(buf)\n\tbuf2 := bufPool.Get().(*[]byte)\n\tdefer bufPool.Put(buf2)\n\tfor left := int(length); left > 0; left -= bufferSize {\n\t\tbs := bufferSize\n\t\tif left < bufferSize {\n\t\t\tbs = left\n\t\t}\n\t\t*buf = (*buf)[:bs]\n\t\t*buf2 = (*buf2)[:bs]\n\t\tif _, err = io.ReadFull(in, *buf); err != nil {\n\t\t\treturn fmt.Errorf(\"src read: %s\", err)\n\t\t}\n\t\tif _, err = io.ReadFull(in2, *buf2); err != nil {\n\t\t\treturn fmt.Errorf(\"dest read: %s\", err)\n\t\t}\n\t\tif !bytes.Equal(*buf, *buf2) {\n\t\t\treturn fmt.Errorf(\"bytes not equal\")\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc compObjBinary(src, dst object.ObjectStorage, key string, abort chan struct{}, obj object.Object) (bool, error) {\n\tvar err error\n\tif obj.Size() < maxBlock {\n\t\terr = compObjPartBinary(src, dst, key, abort, 0, obj.Size())\n\t} else {\n\t\tn := int((obj.Size()-1)/defaultPartSize) + 1\n\t\terrs := make(chan error, n)","sourceCodeStart":558,"sourceCodeEnd":594,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/sync/sync.go#L558-L594","documentation":"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.","triggerScenarios":"Object size changed between HEAD/Listing and the ranged GET; truncated upload on the source; connection dropped mid-read; backend returning short reads.","commonSituations":"Syncing live buckets where a writer is uploading/overwriting the object concurrently; unstable networks; providers with eventual-consistency quirks.","solutions":["Retry the comparison; the wrapped io error tells whether it was UnexpectedEOF (truncation) or a connection error.","Exclude concurrently-written keys from the sync or re-copy the object after the writer finishes.","Verify object size on src matches what listing reported; if not, re-sync the object.","Check for proxy/firewall idle-timeout killing long reads; reduce part size."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// verify reported size before reading\ninfo, err := src.Head(ctx, key)\nif err != nil || info.Size() < offset+length {\n\treturn fmt.Errorf(\"source size changed or too small for %s\", key)\n}","typeGuard":null,"tryCatchPattern":"if err := comparePart(...); err != nil {\n\tif strings.Contains(err.Error(), \"src read: unexpected EOF\") {\n\t\treturn retryCompareWithBackoff(3)\n\t}\n\treturn err\n}","preventionTips":["Avoid syncing keys that writers are actively modifying","Reduce part size on flaky networks to shorten individual reads","Retry transient truncation errors","Re-list objects when size mismatches are detected"],"tags":["io","truncation","object-storage"],"backgroundTag":"file-read-failed","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"}