When two devices concurrently add features to a GeoPackage layer and one needs to rebase against the other's changes, the rebased device's new features receive negative FIDs. The root cause is a silent narrowing cast from int64_t to int (32-bit) in the rebase code, which corrupts FID values whenever sqlite_sequence.seq exceeds INT32_MAX (2,147,483,647).
This was observed in a real project where sqlite_sequence.seq had grown to 77,194,629,200 — well beyond INT32_MAX. The table itself contained only 244 rows (FIDs 1–244), but the high-water mark in sqlite_sequence persisted from a prior operation. With 8 devices collecting data simultaneously, every device except the first to sync received negative FIDs for all newly added features. The pattern was fully deterministic: first sync → positive FIDs, all subsequent syncs → negative FIDs.
Note that sqlite_sequence is intentionally excluded from geodiff changesets (https://github.com/MerginMaps/geodiff/blob/master/geodiff/src/drivers/sqlitedriver.cpp#L232), which means a corrupted seq value is not visible to geodiff and cannot be corrected via normal (diff) sync.
When two devices concurrently add features to a GeoPackage layer and one needs to rebase against the other's changes, the rebased device's new features receive negative FIDs. The root cause is a silent narrowing cast from
int64_ttoint(32-bit) in the rebase code, which corrupts FID values wheneversqlite_sequence.seqexceedsINT32_MAX(2,147,483,647).This was observed in a real project where
sqlite_sequence.seqhad grown to 77,194,629,200 — well beyondINT32_MAX. The table itself contained only 244 rows (FIDs 1–244), but the high-water mark insqlite_sequencepersisted from a prior operation. With 8 devices collecting data simultaneously, every device except the first to sync received negative FIDs for all newly added features. The pattern was fully deterministic: first sync → positive FIDs, all subsequent syncs → negative FIDs.Note that
sqlite_sequenceis intentionally excluded from geodiff changesets (https://github.com/MerginMaps/geodiff/blob/master/geodiff/src/drivers/sqlitedriver.cpp#L232), which means a corrupted seq value is not visible to geodiff and cannot be corrected via normal (diff) sync.