What happened?
Problem: In Receive-Only folders paired with Send-Only folders, Syncthing incorrectly marks newly synchronized directories as "Local Additions" after restart/rescans. This happens because:
- Send-Only peer announces directory with mtime
T1
- Receive-Only creates directory and populates it → local mtime becomes
T2 > T1
- After restart, Receive-Only compares local
T2 > remote T1 → marks as "Local Addition"
- "Override Local Changes" works only until next restart
Key symptoms:
- Only affects directories (typically 128B size in UI)
- Only newly created directories during sync
- "Override Local Changes" provides temporary relief only
- Problem reappears after every Syncthing restart
Reproduction Steps
- Setup:
Peer A: Send-Only
Peer B: Receive-Only
Both: Syncthing 2.0.13 (Linux 64-bit ARM), modTimeWindowS=1
- Folder config (both sides):
type=receive-only (Peer B) / send-only (Peer A)
ignorePermissions=false
syncOwnership=true
receiveOwnership=true
send/receiveExtendedAttributes=false
Env: (the bug is most likely independent of these factors, but system speed might be relevant - see note below)
- BTRFS on HDD
- Many folders (>80)
- Some very large folders (1.5 mio files in some folders, >5mio files total)
- Syncthing DB is on SSD
- Slow computers: mini-PC and raspberrypi 5.
- Trigger:
- Create new directory tree on Send-Only peer (e.g.
mkdir -p test1/test2) and some file inside (e.g. echo foo > test1/test2/bar)
- Wait for sync to Receive-Only peer
- Observe:
Receive-Only UI shows: "test1/test2 128 B" as Local Addition
Note: Maybe this only happens for slow systems and/or very large folders or files, which would add a delay between folder creation and being done writing the file contents inside of it, which leads to a larger timestamp on the folder. On a very fast system/setup the timestamp might just be the same and the bug does not happen.
- Restart Syncthing on Receive-Only → Local Addition reappears
Concrete Example (stat output)
Send-Only peer (stat test1/test2/):
Size: 176 Blocks: 0 EA Block: 4096 directory
Access: 2026-02-11 01:57:56.386214969 +0100
Modify: 2026-02-13 01:00:23.752101053 +0100 <- T1
Change: 2026-02-13 01:00:23.752101053 +0100
Birth: 2026-02-11 01:57:56.386214969 +0100
Permissions: drwxrwxr-x (0775), UID/GID: 1000/1000
Receive-Only peer (stat test1/test2/):
Size: 176 Blocks: 0 EA Block: 4096 Verzeichnis
Access: 2026-02-11 01:00:21.164107965 +0100
Modify: 2026-02-14 01:00:25.305593154 +0100 <- T2 > T1
Change: 2026-02-14 01:00:25.305593154 +0100
Birth: 2026-02-11 01:00:21.164107965 +0100
Permissions: drwxrwxr-x (0775), UID/GID: 1000/1000 <- IDENTICAL
Result: Despite identical permissions/ownership/size, directory shows as "Local Addition" because T2 > T1.
Root Cause (from source analysis)
Directories do receive virtualMtime entries and participate in mtime-based change detection:
lib/scanner/directory.go: fi.Modified = ent.ModTime().UnixNano() ✓
lib/model/stscan.go: Compares fsStat.ModTime() > db.GetVirtualMtime() ✓
lib/folder/receiveonly.go: if localMtime > remoteMtime → markAsLocalAddition() ✓
The issue: Receive-Only logic treats self-induced mtime changes (directory updated when child files created) as legitimate local modifications.
Why documentation is misleading: "Directory mtimes not synced" refers to final-settling after sync completion, but mtimes are read during scanning/indexing and do trigger virtualMtime updates.
Workarounds (tested)
touch on Send-Only: Updates remote virtualMtime → temporarily fixes
- Send&Receive instead of Receive-Only: Eliminates "Local Additions" UI entirely
Expected Behavior
Receive-Only should recognize directories whose contents match the global index as "Up to Date", regardless of self-induced mtime changes during population.
Suggested Fix
In lib/folder/receiveonly.go (pseudocode):
// For directories, only mark as local addition if:
// 1. Contents differ (block hash mismatch), OR
// 2. Permissions/ownership differ, OR
// 3. Directory is empty but remote shows populated
// 4. Directory exists, but is non-existent on remote
if !contentsMatch && !metadataMatch {
markAsLocalAddition()
}
Alternative: During directory creation in Receive-Only, preserve the announced virtualMtime from FileInfo instead of using os.Stat().ModTime() post-population.
Side-Note / Observation:
I also tried fixing the timestamps on the receive-only-side by setting them exactly as they were on the sending side.
But a rescandid not pick up the changes without a restart of Syncthing.
This probably happened, because in memory something like this happens:
localDir.mtime = max(localDir.mtime, remoteDir.mtime)
Thus if the localDir.mtime is set to a lower value as before, it would not pick up the change.
However, after a restart of Syncthing this temporary value in memory does no longer exist and the current mtime of the localDir is read and now (after the fix) no longer is larger than the remote mtime thus in sync.
Environment:
Receive-Only: Ubuntu Trixie, BTRFS, ARM64
Send-Only: Linux Mint, BTRFS, 64-bit Intel/AMD
Syncthing: v2.0.13 everywhere
Syncthing version
v2.0.13
Platform & operating system
Linux arm64
What happened?
Problem: In Receive-Only folders paired with Send-Only folders, Syncthing incorrectly marks newly synchronized directories as "Local Additions" after restart/rescans. This happens because:
T1T2 > T1T2 > remote T1→ marks as "Local Addition"Key symptoms:
Reproduction Steps
Env: (the bug is most likely independent of these factors, but system speed might be relevant - see note below)
mkdir -p test1/test2) and some file inside (e.g.echo foo > test1/test2/bar)Note: Maybe this only happens for slow systems and/or very large folders or files, which would add a delay between folder creation and being done writing the file contents inside of it, which leads to a larger timestamp on the folder. On a very fast system/setup the timestamp might just be the same and the bug does not happen.
Concrete Example (stat output)
Send-Only peer (
stat test1/test2/):Receive-Only peer (
stat test1/test2/):Result: Despite identical permissions/ownership/size, directory shows as "Local Addition" because
T2 > T1.Root Cause (from source analysis)
Directories do receive
virtualMtimeentries and participate in mtime-based change detection:lib/scanner/directory.go:fi.Modified = ent.ModTime().UnixNano()✓lib/model/stscan.go: ComparesfsStat.ModTime() > db.GetVirtualMtime()✓lib/folder/receiveonly.go:if localMtime > remoteMtime → markAsLocalAddition()✓The issue: Receive-Only logic treats self-induced mtime changes (directory updated when child files created) as legitimate local modifications.
Why documentation is misleading: "Directory mtimes not synced" refers to final-settling after sync completion, but mtimes are read during scanning/indexing and do trigger virtualMtime updates.
Workarounds (tested)
touchon Send-Only: Updates remote virtualMtime → temporarily fixesExpected Behavior
Receive-Only should recognize directories whose contents match the global index as "Up to Date", regardless of self-induced mtime changes during population.
Suggested Fix
In
lib/folder/receiveonly.go(pseudocode):Alternative: During directory creation in Receive-Only, preserve the announced
virtualMtimefrom FileInfo instead of usingos.Stat().ModTime()post-population.Side-Note / Observation:
I also tried fixing the timestamps on the receive-only-side by setting them exactly as they were on the sending side.
But a
rescandid not pick up the changes without a restart of Syncthing.This probably happened, because in memory something like this happens:
localDir.mtime = max(localDir.mtime, remoteDir.mtime)Thus if the
localDir.mtimeis set to a lower value as before, it would not pick up the change.However, after a restart of Syncthing this temporary value in memory does no longer exist and the current mtime of the localDir is read and now (after the fix) no longer is larger than the remote mtime thus in sync.
Environment:
Syncthing version
v2.0.13
Platform & operating system
Linux arm64