Bug description
After a hard reset (GPU driver freeze → power button) while the desktop client was downloading files during a sync run, the client re-uploaded 447 files with empty content (0 bytes), overwriting the server-side originals that had been created by other users the same morning.
Root cause chain, fully evidenced by client + server logs:
- Client starts a sync and downloads new remote files. The downloads complete and the sync journal DB records them (path, size, mtime, checksum). The sync DB is fsync'd; the downloaded file data is still in the page cache.
- Machine hard-resets (in our case an amdgpu freeze; any power loss reproduces this). ext4 (ordered mode) journal replay preserves the file metadata (name, mtime) but the unflushed data is lost → files exist locally with 0 bytes and the original mtime.
- On the next start, discovery compares DB vs. local: same mtime, different size — and classifies this as a local modification:
[ info nextcloud.sync.discovery discovery.cpp:1892 ] Processing "…/invoice.pdf" | (db/local/remote) | valid: true/true/db | mtime: 1786005528/1786005528/0 | size: 197806/0/0 | etag: "f459…"//"" | checksum: "SHA1:ed47…"//""
[ info nextcloud.sync.discovery discovery.cpp:1893 ] discovered "…/invoice.pdf" CSyncEnums::CSYNC_INSTRUCTION_SYNC OCC::SyncFileItem::Up
[ info nextcloud.sync.propagator.upload.v1 propagateuploadv1.cpp:132 ] "/…/invoice.pdf" "SHA1:da39a3ee5e6b4b0d3255bfef95601890afd80709" ← SHA1 of the empty string
[ info nextcloud.sync.networkjob.put propagateupload.cpp:89 ] PUT of "https://…/invoice.pdf" FINISHED WITH STATUS "OK" 204
- The server-side originals (created by other users into a group folder) were overwritten with 0 bytes. Because the upload preserves the local mtime (
X-OC-Mtime), the damage is hard to spot: the files keep their plausible timestamps and only the size reveals the loss.
Notably, the client's own log files from the crashed boot were also zeroed by the same ext4 behaviour — confirming the mechanism.
This is the "upload" sibling of #9280 (which covers the deletion case for queued-but-not-downloaded files). Here the files had completed downloading before the crash, so the client had full knowledge (size + checksum) that the local 0-byte content did not match what it had itself written moments earlier.
Expected behaviour
When discovery finds local size == 0 while the sync DB records a non-zero size with an unchanged mtime, the client should not silently propagate the empty file. Options:
- verify the content checksum against the DB before treating it as a local edit (the DB checksum was available:
SHA1:ed47… vs. actual SHA1:da39…),
- treat it as a conflict (keep server version, create a conflict file), or
- at minimum warn, as is done for the "all files deleted" case.
A general "many files shrank to 0 bytes since last run" heuristic (analogous to the mass-deletion warning) would protect against the whole class of post-crash corruption.
Environment
- Desktop client: 33.0.2 (Linux, Tuxedo build
mirall/33.0.2~tux1), sync folder on ext4 (ordered)
- OS: Tuxedo OS (Ubuntu-based), kernel 6.17
- Server: Nextcloud 32.0.13, target was a group folder shared with ~dozens of users
- Trigger: amdgpu freeze → hard reset ~80 s after boot, mid-sync
Steps to reproduce
- Let the client fully download a batch of files during a sync run on ext4.
- Cut power before the page cache is flushed (or
echo b > /proc/sysrq-trigger right after the downloads finish).
- Boot again; observe zero-length local files with preserved mtimes.
- Client uploads the 0-byte files, overwriting server content (no conflict, no warning).
Impact
Silent, hard-to-detect data loss for other users' files (group folder), recoverable only via server-side versioning. 447 files were overwritten in one sync run in our incident.
Bug description
After a hard reset (GPU driver freeze → power button) while the desktop client was downloading files during a sync run, the client re-uploaded 447 files with empty content (0 bytes), overwriting the server-side originals that had been created by other users the same morning.
Root cause chain, fully evidenced by client + server logs:
X-OC-Mtime), the damage is hard to spot: the files keep their plausible timestamps and only the size reveals the loss.Notably, the client's own log files from the crashed boot were also zeroed by the same ext4 behaviour — confirming the mechanism.
This is the "upload" sibling of #9280 (which covers the deletion case for queued-but-not-downloaded files). Here the files had completed downloading before the crash, so the client had full knowledge (size + checksum) that the local 0-byte content did not match what it had itself written moments earlier.
Expected behaviour
When discovery finds
local size == 0while the sync DB records a non-zero size with an unchanged mtime, the client should not silently propagate the empty file. Options:SHA1:ed47…vs. actualSHA1:da39…),A general "many files shrank to 0 bytes since last run" heuristic (analogous to the mass-deletion warning) would protect against the whole class of post-crash corruption.
Environment
mirall/33.0.2~tux1), sync folder on ext4 (ordered)Steps to reproduce
echo b > /proc/sysrq-triggerright after the downloads finish).Impact
Silent, hard-to-detect data loss for other users' files (group folder), recoverable only via server-side versioning. 447 files were overwritten in one sync run in our incident.