SSScreenshotMetadataHarvester app termination

Hi team, We are seeing a high volume of app terminations (uANRs), with most of them sharing the attached stack trace. I’d love to get your input on potential workarounds or fixes we can explore to mitigate this issue.

0 	 CoreFoundation                                -[__NSSingleObjectArrayI countByEnumeratingWithState:objects:count:]  + 132
1 	 ScreenshotServices                            +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 228
2 	 ScreenshotServices                            +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 196
3 	 ScreenshotServices                            +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 196
4 	 ScreenshotServices                            +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 296
5 	 ScreenshotServices                            +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 196
6 	 ScreenshotServices                            +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 196
7 	 ScreenshotServices                            +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 196
8 	 ScreenshotServices                            +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 196
9 	 ScreenshotServices                            +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 296
10 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 196
11 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 196
12 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 296
13 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 296
14 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:] + 196
15 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 196
16 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:] + 296
17 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 196
18 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 196
19 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 296
20 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:] + 196
21 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 196
22 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 196
23 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:] + 196
24 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester _crawlViewController:executingBlock:]  + 196
25 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester _contentRectsForMetadata] + 216
26 	 ScreenshotServices                           +[SSScreenshotMetadataHarvester harvestScreenshotMetadataAndRespondToAction:]  + 628
27 	 UIKitCore                                    -[UIScreenshotMetadataRequestAction fulfillRequest]  + 180
28 	 UIKitCore                                    -[UIApplication _handleNonLaunchSpecificActions:forScene:withTransitionContext:completion:] + 3432
29 	 UIKitCore                                    -[UIScene _emitSceneSettingsUpdateResponseForCompletion:afterSceneUpdateWork:]  + 412
30 	 UIKitCore                                    -[UIScene scene:didUpdateWithDiff:transitionContext:completion:] + 244
31 	 UIKitCore                                    -[UIApplicationSceneClientAgent scene:handleEvent:withCompletion:] + 336
32 	 FrontBoardServices                           __76-[FBSScene updater:didUpdateSettings:withDiff:transitionContext:completion:]_block_invoke.146 (in 1d4f7bf8-ca62-3218-a074-9187a2d191ae) + 252
33 	 FrontBoardServices                           -[FBSScene _callOutQueue_coalesceClientSettingsUpdates:]  + 68
34 	 FrontBoardServices                           -[FBSScene updater:didUpdateSettings:withDiff:transitionContext:completion:]  + 712
35 	 FrontBoardServices                           __94-[FBSWorkspaceScenesClient _queue_updateScene:withSettings:diff:transitionContext:completion:]_block_invoke_2  + 148
36 	 FrontBoardServices                           -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 168
37 	 FrontBoardServices                           __94-[FBSWorkspaceScenesClient _queue_updateScene:withSettings:diff:transitionContext:completion:]_block_invoke.cold.1  + 252
38 	 FrontBoardServices                           __94-[FBSWorkspaceScenesClient _queue_updateScene:withSettings:diff:transitionContext:completion:]_block_invoke  + 184
39 	 libdispatch.dylib                            _dispatch_client_callout + 16
40 	 libdispatch.dylib                            _dispatch_block_invoke_direct  + 284
41 	 FrontBoardServices                           __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ (in 1d4f7bf8-ca62-3218-a074-9187a2d191ae) + 52
42 	 FrontBoardServices                           -[FBSMainRunLoopSerialQueue _targetQueue_performNextIfPossible] (in 1d4f7bf8-ca62-3218-a074-9187a2d191ae) + 240
43 	 FrontBoardServices                           -[FBSMainRunLoopSerialQueue _performNextFromRunLoopSource] (in 1d4f7bf8-ca62-3218-a074-9187a2d191ae) + 28
44 	 CoreFoundation                               __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ (in ae3c9338-0166-397a-9643-356b14f6ee58) + 28
45 	 CoreFoundation                               __CFRunLoopDoSource0 (in ae3c9338-0166-397a-9643-356b14f6ee58) + 172
46 	 CoreFoundation                               __CFRunLoopDoSources0 (in ae3c9338-0166-397a-9643-356b14f6ee58) + 332
47 	 CoreFoundation                               __CFRunLoopRun (in ae3c9338-0166-397a-9643-356b14f6ee58) + 840
48 	 CoreFoundation                               CFRunLoopRunSpecific (in ae3c9338-0166-397a-9643-356b14f6ee58) + 572
49 	 GraphicsServices                             GSEventRunModal (in d372e13f-7505-3add-ae13-062656f0b1f6) + 168
50 	 UIKitCore                                    -[UIApplication _run] (in 5e794caa-4162-3ff6-861e-45f29f6b8ac0) + 816
51 	 UIKitCore                                    UIApplicationMain (in 5e794caa-4162-3ff6-861e-45f29f6b8ac0) + 336
Answered by DTS Engineer in 894059022

Thanks for asking. And thanks for providing a stack crawl. A few observations and a path forward.

What the stack shows: the system invokes UIScreenshotMetadataRequestAction on the main thread during a scene update, which hands off to the screenshot metadata harvester in ScreenshotServices. That harvester recurses through your view-controller tree, visiting each level. Your stack shows roughly 25 levels of recursion ending in a single-element NSArray enumeration at the top. The depth and per-level cost during the crawl are the levers visible from the stack.

Worth checking: does your app have 25-deep nested or presented view controllers? Most apps are well under that. If yours is that deep, depth and per-VC view-tree complexity are where any mitigation would come from. If it isn't, the harvester is going deeper than the apparent VC structure and that itself is a data point worth including with your Feedback.

For diagnostic data: an Instruments Time Profiler trace captured while triggering the metadata harvest shows where the per-level cost concentrates. You can trigger the harvest by briefly backgrounding the app, or by performing whatever action surfaces the termination. MetricKit's MXHangDiagnostic captures hang reports from real devices in the field.

To get this in front of engineering, please file a Feedback report and post the Feedback number here. To make it actionable, include:

  • A sysdiagnose captured shortly after a uANR.
  • An Instruments Time Profiler trace from a uANR moment if you can capture one.
  • App version and OS version distribution from Xcode Organizer, so the team can scope the affected population.
  • The view-controller depth and broad structure of the screen displayed when the harvest ran, if your analytics can give you that.

Thanks for the post and the crash dump. Hard to use on that format.

Kindly submit a comprehensive crash report, adhering to the guidelines outlined in Posting a Crash Report.

https://developer.apple.com/forums/thread/688669

Thanks

Albert  WWDR

Thanks for asking. And thanks for providing a stack crawl. A few observations and a path forward.

What the stack shows: the system invokes UIScreenshotMetadataRequestAction on the main thread during a scene update, which hands off to the screenshot metadata harvester in ScreenshotServices. That harvester recurses through your view-controller tree, visiting each level. Your stack shows roughly 25 levels of recursion ending in a single-element NSArray enumeration at the top. The depth and per-level cost during the crawl are the levers visible from the stack.

Worth checking: does your app have 25-deep nested or presented view controllers? Most apps are well under that. If yours is that deep, depth and per-VC view-tree complexity are where any mitigation would come from. If it isn't, the harvester is going deeper than the apparent VC structure and that itself is a data point worth including with your Feedback.

For diagnostic data: an Instruments Time Profiler trace captured while triggering the metadata harvest shows where the per-level cost concentrates. You can trigger the harvest by briefly backgrounding the app, or by performing whatever action surfaces the termination. MetricKit's MXHangDiagnostic captures hang reports from real devices in the field.

To get this in front of engineering, please file a Feedback report and post the Feedback number here. To make it actionable, include:

  • A sysdiagnose captured shortly after a uANR.
  • An Instruments Time Profiler trace from a uANR moment if you can capture one.
  • App version and OS version distribution from Xcode Organizer, so the team can scope the affected population.
  • The view-controller depth and broad structure of the screen displayed when the harvest ran, if your analytics can give you that.
SSScreenshotMetadataHarvester app termination
 
 
Q