MCRestrictionsPayload (allowListedAppBundleIDs) breaks Apple Watch native app enumeration — `nanotimekitcompaniond` reports "Missing .app from directory: /Watch/"

MCRestrictionsPayload (allowListedAppBundleIDs) breaks Apple Watch app enumeration — nanotimekitcompaniond reports "Missing .app from directory: <iOS-app>/Watch/"

Summary

Installing a Configuration Profile with com.apple.applicationaccess payload containing allowListedAppBundleIDs causes native Apple Watch apps to disappear from the paired Watch — even when their bundle IDs are explicitly in the whitelist. Log analysis shows this is not a bundle ID matching problem: nanotimekitcompaniond on the iPhone fails to enumerate the <companion>.app/Watch/ subdirectories where native watchOS app stubs live.

Follow-up to https://developer.apple.com/forums/thread/745585 — community-confirmed but received no official response.

Environment

  • iPhone 16 (iPhone17,3), iOS 26.4.2 (23E261), supervised
  • Apple Watch paired via Bridge.app
  • Profile installed locally via Apple Configurator (no MDM server required)

Smoking gun

Within ~5 seconds of profile install, two processes (nanotimekitcompaniond and NTKFaceSnapshotService) log identical errors for eight companion-app paths:

nanotimekitcompaniond[1498] <Error>: Missing .app from directory: file:///Applications/MobilePhone.app/Watch/
nanotimekitcompaniond[1498] <Error>: Missing .app from directory: .../Calculator.app/Watch/
nanotimekitcompaniond[1498] <Error>: Missing .app from directory: .../Bridge.app/Watch/
nanotimekitcompaniond[1498] <Error>: Missing .app from directory: .../MobileTimer.app/Watch/
nanotimekitcompaniond[1498] <Error>: Missing .app from directory: .../Camera.app/Watch/
nanotimekitcompaniond[1498] <Error>: Missing .app from directory: .../VoiceMemos.app/Watch/
nanotimekitcompaniond[1498] <Error>: Missing .app from directory: .../MobileMail.app/Watch/
nanotimekitcompaniond[1498] <Error>: Missing .app from directory: .../FindMy.app/Watch/
NTKFaceSnapshotService[3758] <Error>: Missing .app from directory: <same 8 paths>

The Watch's app icons and face complications both go through these processes, which explains the symptoms users see.

iOS itself flags the payload as Watch-incompatible — but applies it anyway

profiled[179] <Notice>: Payload class MCRestrictionsPayload (com.apple.applicationaccess) is not supported on any Watch version
profiled[179] <Notice>: Payload class MCRestrictionsPayload (com.apple.applicationaccess) is not available on HomePod
profiled[179] <Notice>: Beginning profile installation...
profiled[179] <Notice>: Profile "...v2..." installed.

So profiled knows the payload doesn't target watchOS — yet its side effects clearly manifest there.

Tests performed

TestBundle IDs in whitelistResult
v1249 (every installed iOS app: Apple + 3rd party)Walkie-Talkie, Messages, Find My + more disappear from Watch
v2295 (v1 + every Apple extension/Nano* daemon seen in syslog: *.MessagesActionExtension, *.FindMyNotifications*Extension, *.FindMyWidget*, com.apple.NanoBackup, com.apple.NanoMusicSync, com.apple.NanoPreferencesSync, com.apple.NanoTimeKit.face, com.apple.NanoUniverse.AegirProxyApp, com.apple.tursd, com.apple.FaceTime.FTConversationService, com.apple.Bridge.GreenfieldThumbnailExtension, etc.)Identical Missing-.app errors. Same apps disappear.

Conclusion: this is not a bundle ID matching issue — adding more IDs doesn't help. The system fails to enumerate <companion-iOS-app>.app/Watch/ regardless of whitelist contents. Many users in my prior thread reported trying 100+ bundle ID combinations without success; this evidence explains why.

Reproduction (no MDM required)

  1. Pair Apple Watch with iPhone normally.
  2. Generate a Configuration Profile with com.apple.applicationaccess + any non-empty allowListedAppBundleIDs array.
  3. Install via Apple Configurator's cfgutil install-profile, or AirDrop + Settings → Install.
  4. Within ~5 s, nanotimekitcompaniond errors appear (visible via idevicesyslog).
  5. Native Watch apps backed by an iOS companion stub disappear from the Watch's app grid and from face complications.

Hypothesis

MCRestrictionsPayload applies an enumeration filter that does not descend into .app/Watch/ subdirectories when computing visible apps. nanotimekitcompaniond consequently sees those directories as missing, the Watch's Carousel (SpringBoard equivalent) hides the apps, and NTKFaceSnapshotService can't load corresponding complications. Because profiled itself logs the payload as "not supported on any Watch version", this appears to be unintended bleed-through.

Questions for Apple

  1. Is MCRestrictionsPayload / allowListedAppBundleIDs officially supposed to affect Apple Watch apps? profiled says no.
  2. Is there an undocumented bundle ID pattern (e.g. <companion>.watchapp, or a Bridge.app/Watch/ prefix) that needs whitelisting to keep native Watch apps visible?
  3. Is the recommended workaround to use blacklistedAppBundleIDs instead?
  4. Should the enumeration error (Missing .app from directory: .../Watch/) be tracked as a separate watchOS framework bug?

Artifacts

Curated evidence log with timestamps, profile installer events, and the eight Missing-.app errors is attached as forum-post-v2-evidence.log. Full idevicesyslog captures (multiple install/remove cycles, ~2M log lines) and the .mobileconfig files are available on request.

Thanks — looking forward to guidance.

Answered by isach in 887670022

Update — root cause found and a working workaround

I cracked it. Posting the solution here so other admins can stop trying random bundle IDs.

Root cause (confirmed via watchOS sysdiagnose)

When you install a profile with com.apple.applicationaccess + allowListedAppBundleIDs, lsd on the paired Apple Watch immediately sends "uninstalledNotifications" for every PluginKit extension whose bundle ID is NOT in the whitelist. The watch's Carousel then cascades by terminating the parent apps that own those extensions, disguising the action as user initiated quit.

Captured from watchOS sysdiagnose at the moment of profile install:

17:22:56  lsd: Sending uninstalledNotifications for (
   pluginID=com.apple.MobileSMS.MessagesAssistantExtension
   pluginID=com.apple.tincan.SiriExtension
   pluginID=com.apple.SessionTrackerApp.SessionTrackerSiriExtension
)

17:23:13  Carousel: com.apple.MobileSMS:        terminateApplication - uninstalling app (user initiated quit)
17:23:13  Carousel: com.apple.tincan:           terminateApplication - uninstalling app (user initiated quit)
17:23:13  Carousel: com.apple.NanoNowPlaying:   terminateApplication - uninstalling app (user initiated quit)
17:23:13  Carousel: com.apple.SessionTrackerApp:terminateApplication - uninstalling app (user initiated quit)
17:23:13  Carousel: com.apple.HeartRate:        terminateApplication - uninstalling app (user initiated quit)
17:23:13  Carousel: com.apple.DeepBreathing:    terminateApplication - uninstalling app (user initiated quit)

This is why adding more parent-app bundle IDs to the whitelist never helped — the whitelist filter is being applied at the PluginKit level, not the application level.

The workaround

You must whitelist the SiriKit extension bundle IDs of every Apple Watch native app, in addition to the parent bundle ID. Pattern:

com.apple.<app>                         # parent (likely already there)
com.apple.<app>.SiriExtension           # the missing piece
com.apple.<app>.*Extension              # any other PluginKit plugins the app ships

Confirmed critical extensions

For the three apps in my repro:

AppParent bundle IDRequired extension bundle ID
Walkie‑Talkiecom.apple.tincancom.apple.tincan.SiriExtension
Messagescom.apple.MobileSMScom.apple.MobileSMS.MessagesAssistantExtension
Workoutcom.apple.SessionTrackerAppcom.apple.SessionTrackerApp.SessionTrackerSiriExtension

Validation

Two independent install/remove cycles of a profile containing the above (308 bundle IDs total):

Cycle 1 (install v3): 0 Watch-side extensions in uninstalledNotifications. 
                      Walkie-Talkie, Messages, Find My all stayed visible.
Cycle 2 (remove v3 → reinstall v3): same result.

Before the fix, the same plugins were uninstalled on every profile install.

How to discover the extensions for your deployment

The extension bundle IDs can be enumerated directly from the watchOS sysdiagnose. Trigger a sysdiagnose, extract it, then:

# inside the extracted Watch sysdiagnose folder:
log show --info --debug --last 24h \
    --predicate 'eventMessage CONTAINS "pluginID="' \
    system_logs.logarchive \
    | grep -oE 'pluginID=com\.apple\.[a-zA-Z0-9._-]+' | sort -u

Whatever shows up that you care about — add to allowListedAppBundleIDs.

What is still a bug (Apple-side)

The fact that you have to whitelist watchOS-side extensions through an iOS payload that profiled itself logs as "not supported on any Watch version" is the underlying bug. The workaround above is just rerouting around it.

I will keep the FB open and update the OP if Apple responds. For now: shipping this so others stop chasing the parent bundle IDs.

Environment: iPhone 16 / iOS 26.4.2 (23E261), Apple Watch on watchOS 6.3.1 (build 17U208), supervised iPhone, profile installed locally via Apple Configurator (no MDM server needed to reproduce).

Accepted Answer

Update — root cause found and a working workaround

I cracked it. Posting the solution here so other admins can stop trying random bundle IDs.

Root cause (confirmed via watchOS sysdiagnose)

When you install a profile with com.apple.applicationaccess + allowListedAppBundleIDs, lsd on the paired Apple Watch immediately sends "uninstalledNotifications" for every PluginKit extension whose bundle ID is NOT in the whitelist. The watch's Carousel then cascades by terminating the parent apps that own those extensions, disguising the action as user initiated quit.

Captured from watchOS sysdiagnose at the moment of profile install:

17:22:56  lsd: Sending uninstalledNotifications for (
   pluginID=com.apple.MobileSMS.MessagesAssistantExtension
   pluginID=com.apple.tincan.SiriExtension
   pluginID=com.apple.SessionTrackerApp.SessionTrackerSiriExtension
)

17:23:13  Carousel: com.apple.MobileSMS:        terminateApplication - uninstalling app (user initiated quit)
17:23:13  Carousel: com.apple.tincan:           terminateApplication - uninstalling app (user initiated quit)
17:23:13  Carousel: com.apple.NanoNowPlaying:   terminateApplication - uninstalling app (user initiated quit)
17:23:13  Carousel: com.apple.SessionTrackerApp:terminateApplication - uninstalling app (user initiated quit)
17:23:13  Carousel: com.apple.HeartRate:        terminateApplication - uninstalling app (user initiated quit)
17:23:13  Carousel: com.apple.DeepBreathing:    terminateApplication - uninstalling app (user initiated quit)

This is why adding more parent-app bundle IDs to the whitelist never helped — the whitelist filter is being applied at the PluginKit level, not the application level.

The workaround

You must whitelist the SiriKit extension bundle IDs of every Apple Watch native app, in addition to the parent bundle ID. Pattern:

com.apple.<app>                         # parent (likely already there)
com.apple.<app>.SiriExtension           # the missing piece
com.apple.<app>.*Extension              # any other PluginKit plugins the app ships

Confirmed critical extensions

For the three apps in my repro:

AppParent bundle IDRequired extension bundle ID
Walkie‑Talkiecom.apple.tincancom.apple.tincan.SiriExtension
Messagescom.apple.MobileSMScom.apple.MobileSMS.MessagesAssistantExtension
Workoutcom.apple.SessionTrackerAppcom.apple.SessionTrackerApp.SessionTrackerSiriExtension

Validation

Two independent install/remove cycles of a profile containing the above (308 bundle IDs total):

Cycle 1 (install v3): 0 Watch-side extensions in uninstalledNotifications. 
                      Walkie-Talkie, Messages, Find My all stayed visible.
Cycle 2 (remove v3 → reinstall v3): same result.

Before the fix, the same plugins were uninstalled on every profile install.

How to discover the extensions for your deployment

The extension bundle IDs can be enumerated directly from the watchOS sysdiagnose. Trigger a sysdiagnose, extract it, then:

# inside the extracted Watch sysdiagnose folder:
log show --info --debug --last 24h \
    --predicate 'eventMessage CONTAINS "pluginID="' \
    system_logs.logarchive \
    | grep -oE 'pluginID=com\.apple\.[a-zA-Z0-9._-]+' | sort -u

Whatever shows up that you care about — add to allowListedAppBundleIDs.

What is still a bug (Apple-side)

The fact that you have to whitelist watchOS-side extensions through an iOS payload that profiled itself logs as "not supported on any Watch version" is the underlying bug. The workaround above is just rerouting around it.

I will keep the FB open and update the OP if Apple responds. For now: shipping this so others stop chasing the parent bundle IDs.

Environment: iPhone 16 / iOS 26.4.2 (23E261), Apple Watch on watchOS 6.3.1 (build 17U208), supervised iPhone, profile installed locally via Apple Configurator (no MDM server needed to reproduce).

Update — the SiriExtensions workaround does NOT scale. There is no fix inside allowListedAppBundleIDs. Retracting the workaround above. After testing across more devices and iOS versions, no whitelist composition resolves this. Posting an update so other admins stop chasing a dead end.

What broke the original "fix"

The SiriExtensions pattern (<app> + <app>.SiriExtension + <app>.*Extension) worked on iPhone 16 / iOS 26.4.2 + Apple Watch Series 3 / watchOS 6.3.1. It does not generalize.

Reproduced on a second pairing (iPhone 15 / iOS 18.6.2 + modern Watch):

ProfileBundle IDsPayloadScopeResult
Watch-focused (Nano*, Carousel*, .watchapp, SiriExtensions, complications)451SystemAll Watch apps
disappear
Phone-focused superset (third-party + Apple essentials)481UserAll Watch apps disappear

Both lists installed cleanly. Both removed every native Watch app within ~30s.

Ruled out this round

  • Other payloads in the profile triggering propagation — no, an isolated profile with only applicationaccess +

allowListedAppBundleIDs reproduces it

  • PayloadScope: Userno, both User and System reproduce
  • List size or content (Watch-aware vs phone-aware) — no, both fail identically
  • Per-key supportedOS metadata override — no, schema metadata only
  • Wildcard com.apple.* — not a supported value; only com.apple.webapp is documented (Web Clips only)
  • Switching to blockedAppBundleIDs — not viable for kiosk-style allowlists (cannot enumerate "everything except

these few")

Root cause (reconfirmed)

lsd: Sending uninstalledNotifications for (
   pluginID=com.apple.MobileSMS.MessagesAssistantExtension
   pluginID=com.apple.tincan.SiriExtension
   ...
)

Carousel: com.apple.MobileSMS:      terminateApplication - uninstalling app (user initiated quit)
Carousel: com.apple.tincan:         terminateApplication - uninstalling app (user initiated quit)
Carousel: com.apple.NanoNowPlaying: terminateApplication - uninstalling app (user initiated quit)

The Watch's lsd reads the inherited allowListedAppBundleIDs, marks every PluginKit extension not in the list as "uninstalled," and Carousel cascades by terminating the parent apps — disguised as user initiated quit. Meanwhile Apple's own profiled logs MCRestrictionsPayloadHandler not supported on any Watch version at the same moment the propagation happens. The system acknowledges the incompatibility while still executing the propagation. That's the bug.

Why an "exhaustive whitelist" cannot work

The Watch enumerates private extensions (*.notifications, *.appex, daemons, transient extension IDs) that aren't documented. New ones ship with each minor release. The check happens on the Watch side, against the inherited list, so any extension you don't anticipate is nuked at install time. It's not a matter of finding the right N bundle IDs — the check shouldn't be running on the Watch at all.

The only viable fix: DDM com.apple.configuration.watch.enrollment

Declarative Device Management (iOS 16+) lets the MDM server send the Watch its own declarations independent of the iPhone's. The Watch stops inheriting iPhone-side restrictions. For anyone with control over their MDM backend, this is the path. For anyone on a hosted MDM, push your vendor to ship DDM support.

TL;DR for admins arriving from search

  • Confirmed bug in how watchOS handles the inherited restriction. Apple's logs label it unsupported on Watch yet still

apply it.

  • No working whitelist composition. Don't extend the list — I tried up to 481 entries with SiriExtensions,

widgets, complications, watchkit apps, private extensions. Still broken.

  • Removing the profile restores Watch apps after the iPhone re-syncs.
  • Real fix: DDM Watch Enrollment from the MDM server side. No client-side workaround.

Environment: iPhone 15 / iOS 18.6.2 (unsupervised), profile installed locally via Safari + Settings. Independent of any MDM server — reproduces with any local .mobileconfig containing allowListedAppBundleIDs.

MCRestrictionsPayload (allowListedAppBundleIDs) breaks Apple Watch native app enumeration — &#96;nanotimekitcompaniond&#96; reports "Missing .app from directory: /Watch/"
 
 
Q