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

  1. Rerun sync until a pass completes without changes (sync is idempotent; changed objects will be re-copied).
  2. Pause or quiesce writers on the source during sync, or sync from a snapshot/point-in-time copy.
  3. Use incremental sync options so only changed objects are retried on subsequent passes.
  4. 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

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


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