If you haven't already, check out our contributing guidelines.
Version Number: Multiple production versions observed (e.g. 9.3.54–9.3.64)
Reproducible in staging?: Unknown
Reproducible in production?: Yes
Email or phone of affected tester (no customers): N/A — reproduced via production telemetry, not a single test account
Logs: https://stackoverflow.com/c/expensify/questions/4856
Expensify/Expensify Issue URL: https://github.com/Expensify/Expensify/issues/644858
Issue reported by: Internal engineering investigation
What performance issue do we need to solve?
The JS thread is blocked for 10+ seconds (dead clicks / fully unresponsive UI) when large OpenApp, ReconnectApp, and GetMissingOnyxMessages responses arrive in rapid succession. Sentry traces show this drives a storm of Onyx updates and deep equality work across subscribers.
Symptom tracking (aggregate): https://expensify.sentry.io/issues/7323151341/ (~14k events / 90 days)
What is the impact on end-users?
- App appears frozen after navigation, reconnect, or opening reports/search/settings
- Affects iOS, Android, Windows, and Mac (not platform-specific)
- Both new and established accounts
Benchmarks / evidence (from production traces)
Payload sizes observed: ~0.5 MB – 4 MB per response on sessions that should be lightweight.
Pattern A — Same-endpoint stampede
One session fires the same command many times in minutes:
Pattern B — Byte-identical duplicate responses (≤3s apart)
Server returns the same payload twice; client processes duplicate Onyx data:
Pattern C — Cross-command overlap (≤10s)
Example hang timeline (iOS HybridApp 9.3.64-31)
OpenApp on Home — https://expensify.sentry.io/explore/traces/trace/940b5545caec4d5ba1ac8ce1c0b8738b
ReconnectApp on Onboarding_Purpose ~32s later — https://expensify.sentry.io/explore/traces/trace/0df88e7f01bc4a1ea048f491b87f021d
- APP HANG ~52s after open — https://expensify.sentry.io/issues/7323151341/events/8677a76e805d4948bd37c2412b90e3fd/
Proposed investigation / solution direction
Open questions (from internal triage):
- Why are payloads so large? — Possible whole-collection responses; correlate server
output.size in logs for OpenApp / ReconnectApp.
- Why are commands fired repeatedly? — Network flapping vs uncoordinated client callers (e.g.
subscribeToFullReconnect.ts and other call sites).
- Sentry ↔ server correlation — Confirm
requestID still appears in HTTP breadcrumbs for recent sessions.
- Delegate sessions — Check overlap with known
GetMissingOnyxMessages over-fetch in delegate mode (PR in review internally).
- Mitigation — Client in-flight dedup by
updateIDFrom/updateIDTo may help, but root cause (why duplicate/large calls happen) is priority.
Sentry traces above are shareable; customer emails and FullStory remain on the internal issue only.
Platforms
Issue Owner
Current Issue Owner: @adhorodyski
If you haven't already, check out our contributing guidelines.
Version Number: Multiple production versions observed (e.g. 9.3.54–9.3.64)
Reproducible in staging?: Unknown
Reproducible in production?: Yes
Email or phone of affected tester (no customers): N/A — reproduced via production telemetry, not a single test account
Logs: https://stackoverflow.com/c/expensify/questions/4856
Expensify/Expensify Issue URL: https://github.com/Expensify/Expensify/issues/644858
Issue reported by: Internal engineering investigation
What performance issue do we need to solve?
The JS thread is blocked for 10+ seconds (dead clicks / fully unresponsive UI) when large
OpenApp,ReconnectApp, andGetMissingOnyxMessagesresponses arrive in rapid succession. Sentry traces show this drives a storm of Onyx updates and deep equality work across subscribers.Symptom tracking (aggregate): https://expensify.sentry.io/issues/7323151341/ (~14k events / 90 days)
What is the impact on end-users?
Benchmarks / evidence (from production traces)
Payload sizes observed: ~0.5 MB – 4 MB per response on sessions that should be lightweight.
Pattern A — Same-endpoint stampede
One session fires the same command many times in minutes:
ReconnectAppin ~10 min (iOS 9.3.54-7, scan flow, every 8–30s) — https://expensify.sentry.io/explore/traces/trace/6c175d912b7d4bf5b238d131fdcd10a7ReconnectAppin ~5 min (iOS, route change) — https://expensify.sentry.io/explore/traces/trace/688bf8372e4744f3b9fc57afb30eda21GetMissingOnyxMessagesin ~28s (iOS, Report page) — https://expensify.sentry.io/explore/traces/trace/61d5b4e4d45f4fea979548f86352c912ReconnectAppin ~10s (Windows, ~146 KB each, ~2 calls/sec) — https://expensify.sentry.io/explore/traces/trace/298128ff3d274b70860b2060c9fc3581ReconnectAppin ~9s (Windows,/settings/profile/contact-methods) — https://expensify.sentry.io/explore/traces/trace/e3d86d00ed3148bf85d85162c4218e57Pattern B — Byte-identical duplicate responses (≤3s apart)
Server returns the same payload twice; client processes duplicate Onyx data:
ReconnectApp, 516,004 / 516,004 bytes identical, 1s apart (Windows) — https://expensify.sentry.io/explore/traces/trace/61bc0c35ab24458fac3e76592dbcc28bOpenApp, ~1 MB each, ~90s apart (iOS) — https://expensify.sentry.io/explore/traces/trace/44c8c38f52a941f7bf6cd4549fb1bbfdReconnectAppin 2s on/search(Windows) — https://expensify.sentry.io/explore/traces/trace/9d20e02d47d047aeaad3f0afcc82fa1dPattern C — Cross-command overlap (≤10s)
GetMissingOnyxMessages475 KB →ReconnectApp475 KB, 1s apart (Mac, Report) — https://expensify.sentry.io/explore/traces/trace/1d72808fd7c8414e8b86bdc38d349ed1ReconnectApp→GetMissingOnyxMessages, byte-identical 250,893 B, 1s apart (Windows, Home) — https://expensify.sentry.io/explore/traces/trace/da50a56c2ec4443685eada0f86e486e2Example hang timeline (iOS HybridApp 9.3.64-31)
OpenAppon Home — https://expensify.sentry.io/explore/traces/trace/940b5545caec4d5ba1ac8ce1c0b8738bReconnectAppon Onboarding_Purpose ~32s later — https://expensify.sentry.io/explore/traces/trace/0df88e7f01bc4a1ea048f491b87f021dProposed investigation / solution direction
Open questions (from internal triage):
output.sizein logs forOpenApp/ReconnectApp.subscribeToFullReconnect.tsand other call sites).requestIDstill appears in HTTP breadcrumbs for recent sessions.GetMissingOnyxMessagesover-fetch in delegate mode (PR in review internally).updateIDFrom/updateIDTomay help, but root cause (why duplicate/large calls happen) is priority.Sentry traces above are shareable; customer emails and FullStory remain on the internal issue only.
Platforms
Issue Owner
Current Issue Owner: @adhorodyski