WhatsApp Business for iOS dies after 16 seconds when a companion device is linked – Tom Granot
WhatsApp Business for iOS dies after 16 seconds when a companion device is linked
07 Jul, 2026
This is a writeup, mostly generated by AI and follows the writing style of good old MSDN forums and announcements.
I've been blocked from using WhatsApp web for weeks now because of this, so I decided to release the writeup that somewhat unblocked me, if someone else is facing this too.
It has been lightly edited, but mostly is the result of two independent investigation sessions conducted using Fable 5.
Summary<br>WhatsApp Business for iOS on my device is killed by the operating system 13 to 46 seconds after every launch, but only while a companion device (WhatsApp Web or Desktop) is linked to the account. With no linked devices, the application is stable indefinitely.
Over two investigations spanning June and July 2026, three distinct defects were identified in the application's local data, two of which were confirmed and eliminated.
The third and currently active cause is an unbounded per-device receipt-tracking table (receipt_device in MessagingInfraDatabase.sqlite) containing 872,787 rows. Evidence indicates that a launch-time reconciliation routine, active only when a companion device is registered, materializes this table in memory in full.
At approximately 4 KB per materialized row, the resulting allocation reaches the 3,376 MB per-process memory limit, and iOS terminates the process.
The failure is not caused by database corruption, media volume, or account state on WhatsApp's servers. All analysis was performed read-only against decrypted copies of encrypted local iPhone backups. No jailbreak was used and no data was modified on the device.
Environment
Item<br>Value
Device<br>iPhone18,3
OS<br>iOS 26.5.1 (build 23F81)
Application<br>WhatsApp Business (net.whatsapp.WhatsAppSMB), versions 26.22.76 through 26.24.73
Account scale<br>~1.95M messages, ~6,700 chats, ~960k media item records
Primary database<br>ChatStorage.sqlite, 1.6 GB
Analysis host<br>macOS, libimobiledevice, iphone_backup_decrypt, apsw (SQLite)
Symptom<br>When a companion device is linked, the phone application exits to the home screen shortly after launch. The interval between launch and termination was measured at 13, 16, 25, 29, 36, and 46 seconds across six reproductions on July 7. The companion session itself remains connected throughout, because the multi-device architecture serves companions from WhatsApp's servers rather than from the phone. Logging out all companion devices restores full stability; relinking any companion reintroduces the failure on the next launch.
Two secondary kill modes were observed in the same period and are attributed to the same underlying workload:
0xDEAD10CC terminations: the process was suspended while holding a file lock (the SQLite database in the shared app-group container).
diskwrites_resource violations: sustained SQLite write rates of 65 to 93 KB/s against an iOS budget of 12.43 KB/s, exhausting the 1,073.74 MB daily write allowance in three to four hours.
Methodology<br>All conclusions derive from three data sources.
1. iOS crash and resource reports (.ips files), retrieved with idevicecrashreport. These identify the kill reason (jetsam per-process limit, watchdog, suspension-with-lock, disk-write budget) and, for resource violations, include microstackshot samples of the hot path.
2. Encrypted local backups , taken with idevicebackup2 and decrypted selectively with iphone_backup_decrypt. The backup manifest allows individual files to be located and extracted by domain and path without decrypting the full 80 GB archive. Every extracted database was opened immutable to make writes impossible at the API level:
con = apsw.Connection(<br>"file:ChatStorage.sqlite?mode=ro&immutable=1",<br>flags=apsw.SQLITE_OPEN_READONLY | apsw.SQLITE_OPEN_URI)
3. Live syslog capture during reproduction, via idevicesyslog, with the phone connected over USB while the failure was triggered on demand.
Finding 1 (June): a counter at INT32_MAX poisoned the history exporter<br>The June failure mode was a crash during companion history transfer, with mach_vm_allocate failures at modest process footprint and a database that passed PRAGMA integrity_check. That combination (failed allocation, low usage, structurally healthy data) suggested the exporter was sizing a single allocation from a pathological value rather than running out of memory gradually.
A two-stage scan confirmed this. The first stage measured MAX(LENGTH(...)) for every TEXT and BLOB column in the database and ruled out oversized fields; the largest single field in 1.6 GB of data was 130 KB. The second stage took the minimum and maximum of every ID, counter, and sort column:
for c in ("Z_PK", "ZSORT", "ZMESSAGECOUNTER", ...):<br>cur.execute(f"SELECT MIN({c}), MAX({c}), COUNT(*) FROM {t}")
Two anomalies emerged, both parked at 32-bit boundaries:
Field<br>Observed value<br>Organic...