Repository navigation
App Hang Tracking V2 reports false "App Hang Fully Blocked" events when a CarPlay scene keeps the app alive while the phone scene is backgrounded #8317
Description
Platform
iOS
Environment
Production
Installed
CocoaPods
Other Error Monitoring Solution
No
Other Error Monitoring Solution Name
No response
Version
9.18.0
Xcode Version
EAS Build toolchain (Expo SDK 56 default)
Did it work on previous versions?
Unknown... we see the same false positives across our releases going back ~6 weeks (all on cocoa 9.x with App Hang Tracking V2 default-enabled)
Steps to Reproduce
- iOS app with the CarPlay entitlement that presents a
CPWindowscene (turn-by-turn navigation app), plus background location. - Start navigation with CarPlay connected.
- Lock the phone (or background the phone app) while the CarPlay scene stays active. The process keeps running and rendering CarPlay, but the phone's
UIWindowScenestops producing frames. - Unlock/foreground the phone minutes later.
A secondary, CarPlay-free variant reproduces with just background location: background the app mid-navigation then resume ~30 minutes later. Hang events (4-6 s) are reported seconds after the foreground/active transition.
Expected Result
No app hang events. The main thread was never blocked... the app was suspended / not rendering the phone scene. At minimum, hang detection should pause while the phone scene is not producing frames due to backgrounding/lock, as it does for the plain UIApplicationDidEnterBackground case.
Actual Result
App Hang Fully Blocked events whose reported duration exactly matches the backgrounded interval... we've received 22 events across 6 users with durations from 2 s up to 521 s (8.7 min). Two of the events are the fatal variant ("The user or the OS watchdog terminated your app while it blocked the main thread for at least 2000 ms"), presumably suspension followed by swipe-kill/jetsam.
Three signals show these are false positives:
1. The main-thread stack in 21/22 events is the idle run loop, not blocked work:
Thread 0 (main):
mach_msg2_trap
mach_msg2_internal
mach_msg_overwrite
mach_msg
__CFRunLoopServiceMachPort
__CFRunLoopRun
_CFRunLoopRunSpecificWithOptions
GSEventRunModal
-[UIApplication _run]
UIApplicationMain
...
(The 22nd event's main thread was waiting in CAMetalLayerPrivateNextDrawableLocked... the phone-side Metal map layer can't vend a drawable while the display is off, which is also a locked-screen symptom rather than a deadlock.)
2. Breadcrumbs bracket the "hang" with a background→foreground gap. Timeline from the 521 s event:
16:39:10 [http] ... normal navigation traffic (TTS fetches, API calls) ...
16:46:37 [app.lifecycle] {"state":"inactive"}
16:46:37 [app.lifecycle] {"state":"background"}
16:46:39 [http] last request completes
--- ~7.5 minutes of silence (app suspended) ---
16:54:06 [app.lifecycle] {"state":"foreground"}
16:54:06 [app.lifecycle] {"state":"active"}
16:54:06 [ui.lifecycle] {"screen":"CarPlayMapViewController","window":"<CPWindow: ...>", ...}
16:54:24 → event: "App hanging between 521.0 and 521.8 seconds."
The reported duration matches the suspension window, and the first breadcrumb on resume shows the active CPWindow/CarPlayMapViewController scene.
3. contexts.app.in_foreground is true on every event... we suspect the live CarPlay scene keeps UIApplication.applicationState out of .background, defeating the SDK's existing pause-on-background handling for hang tracking (the same handling that was involved in #5907's fix for background launches).
This looks like the CarPlay-scene sibling of #5907 ("App hangs v2 report very high (and invalid) durations", background-launched apps): in both cases the phone UI isn't rendering, V2 sees no frames/heartbeat, and the whole non-rendering interval is attributed to a fully-blocked main thread.
Happy to share full event JSON (stacks, breadcrumbs, contexts) from any of the 22 events privately if useful.
Are you willing to submit a PR?
TBD... but we can definitely test candidate fixes in production (our users hit this on every CarPlay drive)
Activity
linear-code commentedon Jul 2, 2026
COCOA-1611
philippsuess commentedon Jul 2, 2026
Thanks for the detailed report, @sbs44 🙏 — this is a well-diagnosed bug and the breadcrumb/stack signals were very helpful.
TL;DR
.activebut the display isn't producing frames — a CarPlay scene while the phone screen is dark, or (a second customer report) an in-app phone call where the proximity sensor blanks the screen. The non-rendering interval is then misreported as a fully-blocking hang.contexts.app.in_foreground: trueis hardcoded on every app hang event, so it isn't evidence the app was foreground during the hang..inactive(frames tracker pauses onwillResignActive, fix(v8): Wrong Frame Delay when becoming active (#6381) #6393), so the gap is specifically: the app stays.activewhile rendering stops.Technical detail & fix direction
Mechanism. When the frames tracker is running but the
CADisplayLinkstops,getFramesDelayObjCsynthesizes a frame spanningpreviousFrame→now, giving delay ≈ the full window withframesContributingToDelayCount == 1→ classified fully-blocking (SentryDelayedFramesTracker.m:197-234→SentryANRTrackerV2.m:226-234).Why existing guards don't cover it. Detection is gated only by app-aggregate
UIApplicationstate —isApplicationInForeground(background flag) and the frames tracker's pause onwillResignActive(.inactive). Neither fires when the app stays.active. There is no scene-level, proximity, or call/audio-session awareness.Two gaps for phone calls specifically:
.active; proximity blanks the display → nowillResignActive, frames tracker never pauses → false hang..inactive, a hang already in progress isn't cleared, and the duration math excludes only.backgroundtime (SentryANRTrackerV2.m:99-139), not.inactive/paused time — so a long interruption inflates the reported duration.Fix direction: treat "display not rendering" as not-a-hang regardless of why (scene backgrounded, screen off), rather than relying on app-aggregate active state; and exclude
.inactive/paused intervals from hang duration the same way.backgroundis excluded.Repro: deterministic V2 unit test — keep
isApplicationInForeground = true, keep the frames tracker running, stall the display-link wrapper past the timeout, advance time → assert a fully-blocking hang is reported today (bug) / not after the fix.Kobby-Bawuah commentedon Jul 3, 2026
Hey team, we've got another customer hitting this that matches
Gap A (in-app VoIP call, app stays
.activewhile the screen blanks).App Hang Fully Blockedis the bulk of their error volume; durations ~8s up to ~185s, with an idle main thread on every event.Internal ticket: https://app.intercom.com/a/inbox/onh0p2wm/inbox/admin/9242267/conversation/215474890099287?view=List
sbs44 commentedon Aug 11, 2026
Updated numbers from our production data (90-day window), since this is still reproducing on 9.19.1:
__CFRunLoopServiceMachPort→mach_msg2_trap; one each parked inkevent_id/semaphore_timedwait_trap).Two new signals that may help whoever picks up the fix:
Main-thread breadcrumbs continue during the reported hang window. In the 1446 s event,
ui.lifecycleanddevice.orientationbreadcrumbs (both recorded from main-thread notifications) flow throughout the interval the event claims the main thread was fully blocked... the device was mounted on a moving vehicle emitting orientation changes the whole time. This directly contradicts "fully blocked" rather than just implying it from duration.The duration matches the suspension window even hours after backgrounding. An 18-min (1073 s) event: app backgrounded 17:39:30, foregrounded 19:48:56, event fired 19:52:00... the "hang" interval sits entirely inside the backgrounded period, consistent with the duration math only excluding
.backgroundtime when the tracker actually observed the transition (Gap B in your analysis).Possibly related: our
WatchdogTerminationgroup looks like the same mechanism's fatal cousin... suspension-shaped breadcrumb gaps ending at relaunch,usable_memory~11 GB on the most recent event (no memory pressure), across 4 unrelated releases.Offer stands: we can test a candidate fix in production quickly... our users hit this on every CarPlay drive, so we'd have confirmation within a day or two of shipping.
lukas-ruzicka commentedon Aug 11, 2026
Independent confirmation on 9.18.0, with no CarPlay scene and no background-location entitlement — so the underlying fault appears broader than the multi-scene case in the title. Adding our fingerprint since it lines up with yours almost numerically.
Fingerprint (production consumer iOS app, three brand targets):
Fully BlockedandNon Fully Blocked.mach_msg2_trap→__CFRunLoopServiceMachPort→__CFRunLoopRun→GSEventRunModal→-[UIApplication _run], culprit resolving to ourApp.mainentry point. Not one group has an app frame on the main thread, which is what a genuine block would produce.One extra signal that pins the arithmetic: every event's min/max spread is exactly 0.8 s —
3.6–4.4,24.7–25.5,324.0–324.8,518.2–519.0— i.e.2 × sleepIntervalwithappHangTimeoutIntervalat its 2 s default. So the duration comes fromappHangDurationNanos ± sleepIntervalInNanosinSentryANRTrackerV2.detectANRs, and becauseanrStoppedonly fires oncegetFramesDelayfalls back underappHangStoppedFrameDelayThreshold, the reported duration is precisely the interval during which no frames were produced — not an interval during which the main thread was blocked.Where the state gets stuck (read at 9.18.0; the tracker is byte-identical in 9.21.0):
framesContributingToDelayCount == 1over the timeout window.didEnterBackground/didBecomeActive(SentryThreadsafeApplication,sentrycrashstate) pluswillResignActive → SentryFramesTracker.pause().pause()is missed for any reason before rendering stops,isRunningstaystrueandSentryDelayedFramesTracker.previousFrameSystemTimestampfreezes, so the synthesised "current frame" ingetFramesDelayObjCspans every subsequent query window.unpause()'sguard !isRunning else { return }then lets that state survive the round trip — nothing self-heals until frames resume, at which point the entire away interval is emitted as one hang.accumulatedBackgroundTimecannot compensate, since it is keyed on the same notification-derived foreground flag.Suggestion: gate detection on frames having actually been observed recently (or on scene-level activity), rather than on cached app-level notification state. It would also help to re-expose the V1/V2 choice that 9.0 removed — today the only lever is
enableAppHangTracking = false, which discards genuine hang detection along with the noise.mberbet commentedon Aug 15, 2026
Fourth independent fingerprint, from a Capacitor (WKWebView hybrid) fitness app — no CarPlay, no VoIP, no background-location entitlement. It matches the pattern in this thread almost exactly, adds a hybrid-app data point, and includes one clean breadcrumb timeline of a rapid background/foreground-flapping variant.
Environment: sentry-cocoa 9.19.0 via
@sentry/capacitor4.2.0,appHangTimeoutInterval = 2, production iOS.Fingerprint (90-day window):
Fully Blocked, 6Non Fully Blocked. No fatal variant in this group so far.mach_msg2_trap→__CFRunLoopServiceMachPort→__CFRunLoopRun→GSEventRunModal→-[UIApplication _run]→UIApplicationMain). Not one app frame on the main thread.2.1–2.9,29.9–30.7,199.9–200.7,492.4–493.2, …), consistent with2 × sleepIntervalat the 2 s timeout.Timeline of a 29.9–30.7 s
Fully Blockedevent (13 Aug, iPhone17,3, 644 MB free — no memory pressure), showing the rapid-flapping variant:The app transitions background↔foreground twice within one second, performs real work on each transition (our background flush and Live Activity updates complete normally), and is responsive immediately on resume — yet a ~30 s fully-blocking hang is reported. This looks consistent with Gap B from the analysis above: an in-progress "hang" isn't cleared across rapid transitions, and the excluded-time bookkeeping misses part of the away interval.
One contextual note on why some app categories may be hit unusually often: our users flip in and out of the app constantly mid-workout (rest timers, music, notifications), so lifecycle transitions are far more frequent than in a typical app session. Happy to share full event JSON (stacks, breadcrumbs, contexts) privately if useful.
sbs44 commentedon Aug 21, 2026
@NinjaLikesCheez @philipphofmann – checking in on this one. It's been ~7 weeks since filing and ~5 since it was marked high priority; the thread now has four independent fingerprints (CarPlay, VoIP, lifecycle-flapping, and a Capacitor hybrid app) with thousands of events between them.
The frustrating problem on our side: these fire almost daily, and since the only available lever is
enableAppHangTracking = false, we either drown in false "fully blocked" alerts or lose real hang detection entirely.I'm willing to open a PR. Between the fix direction in Philipp's comment and the state-machine analysis from @lukas-ruzicka, the shape seems clear... gate detection on frames actually having been observed rather than cached notification state, and exclude
.inactive/paused intervals from the duration math.... but before I start: would you accept a community PR here, and does that direction look right to you (or is an internal fix already underway that I'd be duplicating)? I have 3 merged PRs across getsentry/sentry-javascript and getsentry/sentry-react-native, but this would be my first rodeo with sentry-cocoa.
mberbet commentedon Aug 21, 2026
Would second accepting a community PR here — the fix direction matches what all four fingerprints in this thread show (idle main-thread stacks + reported duration ≈ the interruption time, not actual blocked time).
Happy to help validate from the Capacitor hybrid side: we can pin a branch build via SPM against our fingerprint and exercise the lifecycle-flapping repro locally, and since our group fires steadily in production (~0.5 events/day across 20+ releases), we can confirm the fix empirically within days of it shipping in a release.
fix: false app hangs when app stops rendering
NinjaLikesCheez commentedon Aug 24, 2026
Absolutely and thank you for being willing to get this across the line! I'd like to rope in @philprime here too since he's looked at App Hang Tracking recently and knows more about that subsystem than I do.
To add some context, we have requested a CarPlay entitlement from Apple but haven't heard back yet - although from reading Philipp's comment it may not be needed.
tlapuste-a commentedon Sep 9, 2026
Fifth fingerprint, and it is the in-app call case from the Gap A description. VoIP app, sentry-cocoa 9.7.0 via
@sentry/react-native8.5.0, App Hangs V2 at the 2 s default.Repro on our app takes ten seconds: start a call, hold the phone to your ear until the proximity sensor blanks the screen, lower it. The SDK reports a fully-blocking hang for the time the screen was dark. My last run on iOS 18.7.8 produced "App hanging between 12.1 and 12.9 seconds" with the main thread in
mach_msg2_trapunder__CFRunLoopRun.In prod over the last 90 days, our largest error issues in our iOS project have been the following 2 hang groups, at about 6x the volume of the next non-hang issue between them:
^percentiles coming from the latest 100 events of each group, with every min/max spread being 0.8s, and every main-thread stack being the idle run loop. Releases span five versions and iOS 17.6 to 26.6 with no correlation to either. From what we've seen, the tail past a minute lines up with device lock and suspension rather than calls, so that also overlaps with the suspension reports in #8899.
We gave in and turned app hang tracking off this week to stop the noise... but it cost us nothing, since not one of our hang groups has ever shown an app frame on the main thread.
One question @NinjaLikesCheez, since it sounds based on #8899 (comment) that the plan is to replace V2 with MetricKit hang reports in v10, is #8840 looking to be a candidate for a 9.x release or is v10 the more likely fix path? If it's v10, a note here would let the rest of this thread stop waiting on the PR.
iOS: disable Sentry app-hang tracking (V2 false positives); bump to 1…
philprime commentedon Oct 16, 2026
Thank you for reporting this issue.
We are aware that our custom app hang tracking solution has some known issues and we're recommending to replace it with MetricKit hang diagnostic reporting instead. App Hangs V1/V2 will be removed in the next major release.
Additionally, we're considering adding a custom hitch detection feature. See #9356 for details.