Keep getting conflicts generated on Android device for files modified only on a desktop PC

Just for the record, I’ve downgraded to v1.21.0 everywhere, as the issue had become literally unbearable, so I’m no longer experiencing the problem at the moment (and I’ve also been able to re-enable conflicts on all devices). I will be waiting eagerly for the proper fix :slightly_smiling_face:.

1 Like

I’ve got some bad news. I’ve just upgraded to v1.22.1 everywhere, and right after doing so, Syncthing began to create the conflicted copies again. This is unrelated to the app, because I’m currently running a self-compiled binary from the command line. The problem must be something that was added in between v1.21.0 and v1.22.0, as there are no conflicted copies when using v1.21.0.

As previously, the conflicted copies themselves are just older versions of the same files. The files themselves are changed only on the PC side while the conflicts are created on Android despite not modifying anything there.

Edit 1

I can reproduce at will when I edit the file on my desktop PC manually. The Android side immediately creates a conflict when the file gets synced there.

Edit 2

I think the debug logs from https://forum.syncthing.net/t/keep-getting-conflicts-generated-on-android-device-for-files-modified-only-on-a-desktop-pc/19060/8 are still relevant, as the situation is basically the same right now. I can provide more logs if needed.

Both the logging and the behavior is different, so new logs showing the issue would be preferable.

For some reason I couldn’t get the conflicts at will after restarting Syncthing with the -logfile option added, but I left it running overnight, and here is the log (with db,model enabled).

The file in question is youtube/index.html. I’ve skimmed through the log myself, and I may of course be wrong here, but these kind of entries look suspicious to me.

[OW324] 2022/11/03 06:46:49.615165 folder_sendrecv.go:1673: DEBUG: receiveonly/j2kgm-h9kws@0x4000a42c00 closing youtube/index.html
[OW324] 2022/11/03 06:46:49.616207 folder_sendrecv.go:1911: DEBUG: receiveonly/j2kgm-h9kws@0x4000a42c00 new error for youtube/index.html: finishing: checking existing file: file modified but not rescanned; will try again later
[OW324] 2022/11/03 06:46:49.658270 folder_sendrecv.go:1673: DEBUG: receiveonly/j2kgm-h9kws@0x4000a42c00 closing youtube/index.html
[OW324] 2022/11/03 06:46:49.658668 folder_sendrecv.go:1911: DEBUG: receiveonly/j2kgm-h9kws@0x4000a42c00 new error for youtube/index.html: finishing: checking existing file: file modified but not rescanned; will try again later
[OW324] 2022/11/03 06:46:49.696189 folder_sendrecv.go:1673: DEBUG: receiveonly/j2kgm-h9kws@0x4000a42c00 closing youtube/index.html
[OW324] 2022/11/03 06:46:49.696603 folder_sendrecv.go:1911: DEBUG: receiveonly/j2kgm-h9kws@0x4000a42c00 new error for youtube/index.html: finishing: checking existing file: file modified but not rescanned; will try again later
[OW324] 2022/11/03 06:46:49.854562 transactions.go:649: DEBUG: new global for "youtube/index.html" after update: {{Version:{[{D4DZUGP 1667448501} {UDPWEVD 1667383324} {44CRNGM 1640458805}]}, Deleted:false, Devices:{D4DZUGP, 7777777}, Invalid:{}}, {Version:{[{D4DZUGP 1667425231} {UDPWEVD 1667383324} {44CRNGM 1640458805}]}, Deleted:false, Devices:{XZZTDIY}, Invalid:{}}, {Version:{[{D4DZUGP 1667373272} {UDPWEVD 1667383324} {44CRNGM 1640458805}]}, Deleted:false, Devices:{UDPWEVD}, Invalid:{}}}
[OW324] 2022/11/03 06:46:49.854756 transactions.go:775: DEBUG: local need delete; folder="j2kgm-h9kws", name="youtube/index.html"
[OW324] 2022/11/03 06:46:49.854947 lowlevel.go:260: DEBUG: adding sequence; folder="j2kgm-h9kws" sequence=13151 youtube/index.html
[OW324] 2022/11/03 06:46:49.856049 folder_sendrecv.go:194: DEBUG: receiveonly/j2kgm-h9kws@0x4000a42c00 changed 1 on try 1
[OW324] 2022/11/03 06:46:49.860997 folder_sendrecv.go:1824: DEBUG: receiveonly/j2kgm-h9kws@0x4000a42c00 scheduling scan after pulling for youtube/index.sync-conflict-20221103-064649-D4DZUGP.html

The situation overall looks like this. All other folders had been paused on purpose to remove noise from the log.

Has anyone got any ideas what the problem may be about? :worried:

I can provide more/other debug logs if needed. Currently, I’ve downgraded to v1.21.0 again, as Syncthing is basically unusable in this state. I’m suspecting the problem is still related to the ownership/extended attributes sync feature (which I don’t actually use), but nevertheless something must be responsible for creating these conflicts. The problem goes away completely as soon as I downgrade to the older version though.

Could be the inode change time check, which is new. If the underlying FS doesn’t support it, like FAT, it probably returns the mtime instead, which is fine. If the underlying FS is a lie and the mtime/inode-change-time fluctuates, as might be the case on Android, weird things will happen. Maybe we should disable that code on Android. You, as a self-compiler, might try to add a if runtimeos.IsAndroid { return time.Time{} } at the top of (basicFileInfo)InodeChangeTime() in fs/basicfs_fileinfo_linuxish.go.

Done! Let’s see what happens. Does it matter that modTimeWindowS is already set to 2 by default on Android, or is the “inode change time check” completely unrelated?

Entirely unrelated, though quite possibly it should be disabled when the mod time window != 0 for similar reasons.

The code change seems to have fixed the problem (although I’m still going to wait till tomorrow to be 100% sure). Do you think that checking for modTimeWindowS would be enough (as it’s automatically used in Android on FAT anyway) or rather should the check be done for Android and modTimeWindowS independently?

Probably disable comparing inode change times if there is a modtime window, I think this could be done in the fileinfo comparison function, it already knows about the modtime window.

To be honest, my confidence when editing the Go code is very low, but I’ve tried doing something like this, i.e.

change

to

// If we are recording inode change times and it changed, they are not
// equal.
if comp.ModTimeWindow == 0 && ((f.InodeChangeNs != 0 && other.InodeChangeNs != 0) && f.InodeChangeNs != other.InodeChangeNs) {
	return false
}

Is this change correct and what you meant above?

I still need to take a closer look and think this through, so just some quick though: Shouldn’t a time (whether modification or inode) change only not cause a conflict, resp. the conflict should be resolved silently without a copy? And if time shenanigans happen as with mtime, inode time should probably get the same treatment (DB backed time, a window, …).

The problem is that these conflicts happen when actually updating the file (i.e. changing its contents) on another device :confused:, so I’m not really sure what is going on under the hood specifically, but the modification proposed by @calmh in https://forum.syncthing.net/t/keep-getting-conflicts-generated-on-android-device-for-files-modified-only-on-a-desktop-pc/19060/17 seems to have fixed the issue nevertheless, as there have been no conflicts for the last 24 hours.

I think I may be experiencing this problem too. I first noticed it a few days ago.

After running fine for many months I started seeing sync conflict files for simple text files I edited on Linux. Those files get synced to one other Linux system and two Android phones.

If I edit the file on Android I don’t get the sync conflict files, but they almost instantly appear after any minor edit on Linux.

After reading this thread I’m guessing they started after and are related to the latest Syncthing update. I’ll do some digging and would appreciate any pointers.

Also ran into the same Issue. Windows, Linux Raspberry Pi work just fine on 1.22.1 . But as soon as I enable the Android client I get conflicts on every change. My Android is a Pixel 4a 5g on Android 13

I can help debug if needed

The thing I am still curious about (though not necessary for broad fixes): When does android report a new inode/c-time? The times in the logs look reasonable, but clearly they get updated too often.

To fix the problem generally, I propose the following two changes (will PR):

Ignore inode time for comparisons if neither xattrs nor ownership is enabled. To contain any issues with those features on all the systems they make no sense to use on (or simply aren’t used). It also just creates index/version vector churn.

Don’t bump the version in the scanner if only inode time changed, but everything else stayed the same.

I think that’s an overly broad disablement, we already had bugs related to some changes being considered not important enough to actually pass to the database etc.

We have the mtime window for systems without reasonable mtime semantics, I think using that to disable the inode time check as well makes enough sense.

What about systems misbehaving with respect to inode time that aren’t FAT and don’t have a window? I don’t see any value in considering inode time when it has no effect, while on the other hand it clearly can cause pretty significant issues. The previous bugs about “information that isn’t important enough” only mattered when any of the opt-in flags were enabled. Ignoring inode time for comparison addresses the default use case and won’t change the behaviour with flags enabled.

Also inode time really is a local thing (given it changes on pull as we don’t set it). So bumping the version just because inode time changed, but nothing else did, is at best useless, at worst misleading - it would have prevented the conflicts (inode change will still be persisted to db).

And what’s the connection of the mod time window to the inode time? Seems like android is misbehaving on inode time and also has a mod time window, and I guess it’s somewhat likely that a system with “not ideal mtime” also has issues with ctime, but is there any actual link? For android I’d actually guess on some virtualisation layer or management process causing inode time bumps than something FAT-like misbehaving (if FAT is even a thing still on android, don’t think so).

I also PRed the two changes, in case we do want to follow any of them (or not).

I’m not sure there are any such systems? I mean, there could be of course, but this seems like something that’s either tracked or it isn’t, and if it isn’t we’ll probably get back either zero time or the mtime, either of which should be fine. It’s just that FAT doesn’t manage to keep mtime either and Android maybe just makes up all the change times based on pure fantasy…

Anyway, I agree we don’t need to create and send a version if the only thing that changed was the inode time, obviously. I’m undecided on whether it’s a good idea to track it anyway or not… will sleep on it and look at your patches.

1 Like