juicedata/juicefs · warning
%s changed during sync. Original: size=%d, mtime=%s; Current
Error message
%s changed during sync. Original: size=%d, mtime=%s; Current: size=%d, mtime=%s
What it means
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.
Source
Thrown at pkg/sync/sync.go:1246
}
}
func checkChange(src, dst object.ObjectStorage, obj object.Object, key string, config *Config) error {
if obj == nil || config.Links && obj.IsSymlink() {
return nil // ignore symlink
}
if cur, err := src.Head(ctx, key); err == nil {
if !config.CheckAll && !config.CheckNew {
checked.Increment()
checkedBytes.IncrInt64(obj.Size())
}
equal := cur.Size() == obj.Size()
if equal && !cur.Mtime().Equal(obj.Mtime()) {
// Head of an object may not return the millisecond part of mtime as List
equal = cur.Mtime().Unix() == obj.Mtime().Unix() && cur.Mtime().UnixMilli()%1000 == 0
}
if !equal {
return fmt.Errorf("%s changed during sync. Original: size=%d, mtime=%s; Current: size=%d, mtime=%s",
cur.Key(), obj.Size(), obj.Mtime(), cur.Size(), cur.Mtime())
}
if dstObj, err := dst.Head(ctx, key); err == nil {
if cur.Size() != dstObj.Size() {
return fmt.Errorf("copied %s size mismatch: original=%d, current=%d", key, obj.Size(), dstObj.Size())
}
return nil
} else {
return fmt.Errorf("check %s in %s: %s", key, dst, err)
}
} else if errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("object %s was removed during sync", key)
} else {
return fmt.Errorf("check %s in %s: %s", key, src, err)
}
}
func copyLink(src object.ObjectStorage, dst object.ObjectStorage, key string) error {View on GitHub (pinned to c9a67b23e8)
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.
Example fix
// quiesce the writer before syncing # pg_dump ... > snapshot.sql && juicefs sync snapshot.sql dst:bucket/ // instead of syncing the live, changing DB files
Defensive patterns
Strategy: retry
Validate before calling
// before syncing, snapshot source state; after sync, compare listings
before, _ := listWithMtime(src, prefix)
after, _ := listWithMtime(src, prefix)
if !equalListings(before, after) { return fmt.Errorf("source is changing; rerun or snapshot") } Try / catch
if err := sync(...); err != nil {
if strings.Contains(err.Error(), "changed during sync") {
logger.Warnf("source mutated during sync, rerunning: %v", err)
return retryUntilStable(sync, maxPasses)
}
return err
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- some errors occurred, please check the log of fsck
- failed to get startTS, which is required for TiKV to ensure
- closed
- errDirSuffix
- ErrSkipped
AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06).
Data as JSON: /api/errors/9e195821d35bdaaf.
Report an issue: GitHub.