{"record":{"id":"9e195821d35bdaaf","repo":"juicedata/juicefs","slug":"s-changed-during-sync-original-size-d-mtime","errorCode":null,"errorMessage":"%s changed during sync. Original: size=%d, mtime=%s; Current: size=%d, mtime=%s","messagePattern":"(.+?) changed during sync\\. Original: size=(.+?), mtime=(.+?); Current: size=(.+?), mtime=(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/sync/sync.go","lineNumber":1246,"sourceCode":"\t}\n}\n\nfunc checkChange(src, dst object.ObjectStorage, obj object.Object, key string, config *Config) error {\n\tif obj == nil || config.Links && obj.IsSymlink() {\n\t\treturn nil // ignore symlink\n\t}\n\tif cur, err := src.Head(ctx, key); err == nil {\n\t\tif !config.CheckAll && !config.CheckNew {\n\t\t\tchecked.Increment()\n\t\t\tcheckedBytes.IncrInt64(obj.Size())\n\t\t}\n\t\tequal := cur.Size() == obj.Size()\n\t\tif equal && !cur.Mtime().Equal(obj.Mtime()) {\n\t\t\t// Head of an object may not return the millisecond part of mtime as List\n\t\t\tequal = cur.Mtime().Unix() == obj.Mtime().Unix() && cur.Mtime().UnixMilli()%1000 == 0\n\t\t}\n\t\tif !equal {\n\t\t\treturn fmt.Errorf(\"%s changed during sync. Original: size=%d, mtime=%s; Current: size=%d, mtime=%s\",\n\t\t\t\tcur.Key(), obj.Size(), obj.Mtime(), cur.Size(), cur.Mtime())\n\t\t}\n\t\tif dstObj, err := dst.Head(ctx, key); err == nil {\n\t\t\tif cur.Size() != dstObj.Size() {\n\t\t\t\treturn fmt.Errorf(\"copied %s size mismatch: original=%d, current=%d\", key, obj.Size(), dstObj.Size())\n\t\t\t}\n\t\t\treturn nil\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"check %s in %s: %s\", key, dst, err)\n\t\t}\n\t} else if errors.Is(err, os.ErrNotExist) {\n\t\treturn fmt.Errorf(\"object %s was removed during sync\", key)\n\t} else {\n\t\treturn fmt.Errorf(\"check %s in %s: %s\", key, src, err)\n\t}\n}\n\nfunc copyLink(src object.ObjectStorage, dst object.ObjectStorage, key string) error {","sourceCodeStart":1228,"sourceCodeEnd":1264,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/sync/sync.go#L1228-L1264","documentation":"Raised by checkChange during sync verification: after copying, the source object was re-Headed and its size or mtime no longer matches what was listed at sync start. The sync cannot guarantee a consistent copy because the source changed during the run.","triggerScenarios":"sync verifies each copied object via src.Head and compares Size and Mtime with the originally listed obj; size differs, or mtime differs (unless the mtime lacks sub-second precision and seconds match), producing this error.","commonSituations":"Active workloads writing to the source while sync runs (log files, databases, growing datasets); the source is a mutable store being continuously updated; very large syncs that take long enough for objects to change underneath.","solutions":["Rerun sync until a pass completes without changes (sync is idempotent; changed objects will be re-copied).","Pause or quiesce writers on the source during sync, or sync from a snapshot/point-in-time copy.","Use incremental sync options so only changed objects are retried on subsequent passes.","For continuously-changing sources, exclude those keys/prefixes from the sync."],"exampleFix":"// quiesce the writer before syncing\n# pg_dump ... > snapshot.sql && juicefs sync snapshot.sql dst:bucket/\n// instead of syncing the live, changing DB files","handlingStrategy":"retry","validationCode":"// before syncing, snapshot source state; after sync, compare listings\nbefore, _ := listWithMtime(src, prefix)\nafter, _ := listWithMtime(src, prefix)\nif !equalListings(before, after) { return fmt.Errorf(\"source is changing; rerun or snapshot\") }","typeGuard":null,"tryCatchPattern":"if err := sync(...); err != nil {\n  if strings.Contains(err.Error(), \"changed during sync\") {\n    logger.Warnf(\"source mutated during sync, rerunning: %v\", err)\n    return retryUntilStable(sync, maxPasses)\n  }\n  return err\n}","preventionTips":["Quiesce writers or sync from a snapshot for mutable data.","Run sync repeatedly until a clean pass completes; it's idempotent.","Exclude continuously changing prefixes with --exclude.","Schedule syncs in quiet windows for log/database sources."],"tags":["sync","consistency","source-changed"],"backgroundTag":"source-modified-during-sync","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}