UNNotificationAttachment preview intermittently missing (attachment-store URL becomes unreadable)

I have been fighting this problem for two months and would love any help, advice or tips. Should I file a DTS ticket?

Summary We attach a JPEG image to a local notification using UNNotificationAttachment. iOS reports the delivered notification as having attachments=1, but intermittently no image preview appears in Notification Center. In correlated cases, the attachment’s UNNotificationAttachment.url (which points into iOS’s attachment store) becomes unreadable (Data(contentsOf:) fails) even though the delivered notification still reports attachments=1.

This document describes the investigation, evidence, and mitigations attempted.

Product / Component

  • UserNotifications framework
  • UNNotificationAttachment rendering in Notification UI (Notification Center / banner / expanded preview)

Environment

  • App: OnThisDay (SwiftUI, Swift 6)
  • Notifications: local notifications scheduled with UNCalendarNotificationTrigger(repeats: false)
  • Attachment: JPEG generated from PhotoKit (PHImageManager.requestImage) and written to app temp directory, then passed into UNNotificationAttachment.
  • Test contexts:
    • Debug builds (direct Xcode install)
    • TestFlight builds (production signing)
  • iOS devices: multiple, reproducible with long runs and user clearing delivered notifications

Expected Result

  • Delivered notifications with UNNotificationAttachment should consistently show the image preview in Notification Center (thumbnail and expanded preview), as long as the notification reports attachments=1.
  • If the OS reports attachments=1, the attachment’s store URL should remain valid/readable for the lifetime of the delivered notification still present in Notification Center.

Actual Result

Intermittently:

  • Notification Center shows no image preview even though the app scheduled the notification with an attachment and iOS reports the delivered notification as having attachments=1.
  • When we inspect delivered notifications via UNUserNotificationCenter.getDeliveredNotifications, the delivered notification’s request.content.attachments.first?.url exists but is unreadable (attempting Data(contentsOf:) returns nil / throws), i.e. the backing attachment-store file appears missing or inaccessible.

In some scenarios the attachment-store file is readable for hours while the notification is pending, and then becomes unreadable after the notification is delivered.

Reproduction Scenarios (Observed)

Next-day reminders show attachment-store unreadable after delivery

1. Schedule a one-shot daily reminder for next day (07:00 local time) with UNCalendarNotificationTrigger(repeats: false) and a JPEG attachment. 2. During the prior day, periodic background refresh tasks verify the pending notification’s attachment-store URL is readable (pendingReadable=true). 3. After the reminder is delivered the next morning, the delivered snapshot shows the delivered notification’s attachment-store URL is unreadable (readable=false) and Notification Center shows no preview.

Interpretation: the attachment-store blob appears to become inaccessible around/after delivery, despite being readable while pending.

Evidence and Instrumentation

We added non-crashing diagnostic logging (Debug builds) around:

Scheduling time

  • Logged that we successfully created a UNNotificationAttachment from a unique temp file.
  • Logged that UNUserNotificationCenter.add(request) succeeded.
  • Queried pendingNotificationRequests() and logged the scheduled request’s attachment url.lastPathComponent (iOS attachment-store filename).

Delivered time (when app becomes active)

  • Called UNUserNotificationCenter.getDeliveredNotifications and logged:
    • delivered count, attachment count
    • attachment url.lastPathComponent
    • whether Data(contentsOf: attachment.url) succeeds (readable=true/false)

Content fingerprinting

  • Fingerprinted the exact JPEG bytes we wrote (SHA-256 prefix + byte count).
  • Logged the iOS attachment-store filename (url.lastPathComponent) returned post-scheduling.

Decode validation probe (later addition)

  • When Data(contentsOf:) succeeds, we validate it decodes as an image using CGImageSourceCreateWithData and log:
    • UTI (e.g. public.jpeg)
    • pixel width/height
    • magic header bytes

What we tried / Mitigations

Proactive “self-heal” for pending notifications

Change: during background refresh/foreground refresh, verify the pending daily reminder’s attachment-store URL readability. If it’s unreadable, reschedule with a new attachment (same trigger).

Rationale: if iOS drops the store file before delivery, recreating could repair it.

Result: We observed cases where pending remained readable but delivered became unreadable after delivery, so this doesn’t address all observed failures. It is still valuable hardening.

Increase scheduling frequency / reschedule closer to fire time (proposed/considered)

We discussed adding a debug mode to always recreate the daily reminder during background refresh tasks (or only within N hours of fire time) to reduce the time window between attachment creation and delivery.

Status: experimental; not yet confirmed to resolve the “pendingReadable=true → delivered unreadable after delivery” failure.

Impact

  • The primary UX value of the daily reminder is the preview photo; missing previews degrade core functionality.
  • Failures are intermittent and appear dependent on OS attachment-store behavior and Notification Center actions (clearing notifications), making them difficult to mitigate fully app-side.

Notes / Questions for Apple

1. Is iOS allowed to coalesce/deduplicate UNNotificationAttachment storage across notifications? If so, what is the retention model when delivered notifications are removed? 2. If a delivered notification still reports attachments=1, should its attachment-store URL remain valid/readable while the notification is still present in Notification Center? 3. In “next-day” one-shot scheduling scenarios, can the attachment-store blob be purged between scheduling and delivery (or immediately after delivery) even if the notification remains visible? 4. Is there a recommended pattern to ensure attachment previews remain stable for long-lived scheduled notifications (hours to a day), especially when using UNCalendarNotificationTrigger(repeats: false)?

Minimal Code Pattern (simplified)

1. Generate JPEG (PhotoKit → UIImage → JPEG Data). 2. Write to a unique temp URL. 3. Create attachment:

  • UNNotificationAttachment(identifier: <uuid>, url: <tempURL>, options: [UNNotificationAttachmentOptionsTypeHintKey: "public.jpeg"])

4. Schedule notification with a calendar trigger for the next morning.

Thanks for the detailed information and diagnostic steps. This makes me believe you have debugged your end adequately, and we are not running into an invalid image, or something simple as that.

It might be more suitable to file a Feedback Report than a DTS ticket, so the Notifications team can take a look as to why the store might be becoming inaccessible.

The question that comes to my mind is whether this happens when the device is locked and the system Notifications setting is set to not show previews (Settings -> Notifications -> Show Previews) when the device is locked. If that is not set to "Always" could you try with setting it to Always.

I don't really believe this could be the case as you mention the app being active, but it's an easy test to see if that setting has any effect on the issue.

Regardless, this would best be handled as a bug report with diagnostic logs. Here are the steps to obtain logs.

First , please go to https://developer.apple.com/bug-reporting/profiles-and-logs/ and follow the instructions for APNS (Apple Push Notification Service) to install a logging profile on your device. I know you are using local notifications, but that profile will help in either case.

Next is to reproduce the problem. Which might be tricky in this situation due to (A) the time span between scheduling the notification, (B) when the attachment store might be getting corrupted, and (C) you see the notification without the image.

The issue is, the most detailed debug level logs are only saved for the last while, and that is going to be way shorter than a day that you say it takes for the problem to reproduce.

Catching (A) and (C) are easy, but catching (B) might be tricky.

One way, if you can, would be to take sysdiagnoses First right after (A), then every few hours between (A) and (C) and right after (C). The team might be confused with all this, but I will assist in explaining.

The above link includes instructions on how to trigger the sysdiagnoses as well. So, the best would be:

  1. install the logging profile
  2. schedule the notification in your app
  3. take a sysdiagnose
  4. take more sysdiagnoses until you see the store inaccessible, until the notification triggers
  5. take the last sysdiagnose

If you can reliably reproduce the issue with a shorter period trigger, that would be ideal of course.

As this seems to happen intermittently, I am also suspecting that some system event, rather than passing of time could be the cause. Are you able to recognize a pattern of when this happens, what might have happened before (between A and C). Restart? A memory hog app might have been used that caused some processes to be jetsamed? Would you have been updating your app with a new build in between? And, I am sure you must have checked it, but to double check, that your image file is not corrupted.

If the problem becomes more reproducible, it would be easier to find the root case.

In any case, do your best to collect sysdiagnoses for the issue, and then use https://feedbackassistant.apple.com/ to describe your problem in detail as you have done it here, attach the sysdiagnoses and any other logs you might have, a small sample project if you have it.

Once done, post the Feedback ID here, and @mention me so I can make sure it is routed correctly.

Then we'll take it from there.


Argun Tekant /  WWDR Engineering / Core Technologies

UNNotificationAttachment preview intermittently missing (attachment-store URL becomes unreadable)
 
 
Q