CTFontManagerCreateFontRequestRunLoopSource does not receive events in macOS 27

CTFontManagerCreateFontRequestRunLoopSource does not receive any font requests on macOS 27, since beta 5. This API worked fine until macOS 27 beta 4, including previous macOS releases.

It looks like this is caused by the App Sandbox. When the com.apple.security.app-sandbox entitlement is disabled the font request source does receive events.

Report including sample project: FB24764122

let source = CTFontManagerCreateFontRequestRunLoopSource(0, { (dict, pid) in /* does not receive events when sandboxed */ }
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, .defaultMode)

Is this a deliberate change or is this a bug in macOS 27? Is there an entitlement that can be set to enable the API in sandboxed apps?

My application is distributed on the Mac App Store and as standalone app. Both are properly sandboxed for added security. Disabling the App Sandbox for this specific API would be very undesirable as users will lose all Sandbox benefits.

You attached a sysdiagnose log to your bug but it looks like that log was from macOS 15.7.9. Please reproduce the problem on macOS 27, immediately grab a sysdiagnose log on that Mac, attach it to your bug, and then reply here when you’re done.

ps I have lots of bug reporting hints and tips in Bug Reporting: How and Why?

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks for looking into it! I've ran the sample app a few times and added the sysdiagnose log generated by the Feedback Assistant.

PS. the "File effective bug reports" link in your Bug Reporting tips topic seems to redirect to an unrelated page. If I did it incorrectly or you need more info/details please let me know :)

the "File effective bug reports" link in your Bug Reporting tips topic seems to redirect to an unrelated page.

Yeah, that’s weird. The link used to work. I’ve made a note to fix this. Thanks for the heads up.

I've ran the sample app a few times and added the sysdiagnose log generated by the Feedback Assistant.

Cool.

I’m not seeing the info I expect to see in those logs, so lemme ask you a question. The test project you attached to the bug report builds an app called FontRequest with a bundle ID of com.example.FontRequest. Is that the same sample app you ran before triggering the sysdiagnose log?

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Is that the same sample app you ran before triggering the sysdiagnose log?

Yes.

I repeated the steps on a different Mac and added it to the report. Ran the sample app a few times, then added "Device Diagnostics" in Feedback Assistant. Then it's gathering info, I'm not sure if I should launch the app during gathering or before that, but I did both in this case.

The system_logs.logarchive seem to include entries for com.example.FontRequest

If I did it incorrectly please let me know.

I'm currently investigating alternatives in case the API will not be available anymore when sandboxed. I've read some of your posts about XPC, so perhaps you can give your opinion on the following workaround:

Standalone distributed app:

  • Keep app sandboxed
  • Add non-sandboxed bundled XPC Service
  • Run the API in XPC Service and communicate with app when necessary

Mac App Store app:

  • everything must be sandboxed so cannot bundle XPC Service
  • Provide external non-sandboxed Helper app with same group container as main app
  • Communicate with external Helper app via XPC and group container

Side question: should I use the iOS-style group identifier for this (according to https://developer.apple.com/forums/thread/721701) or should I use the macOS style Team ID prefix for the group container to communicate with the external XPC helper app?

That function's been deprecated since 10.6. This is why people shouldn't sit on deprecated functions. Maybe you could have come up with a workaround, or filed an enhancement request for an alternative.

You can include a non-sandboxed XPC, but the entire function could go away. And your Mac App Store route is a whole different can-o-worms. It's one thing to have a technical barrier, now you're talking policy, user experience, and App Review barriers. That's bad.

What does this function actually do for you?

If I did it incorrectly please let me know.

Nah, I suspect I was ‘holding it wrong’ at my end. I re-ran my queries today and got sensible results.

However, those results didn’t shed any light on this problem. I unpacked your sysdiagnose log and then ran a query against the system log snapshot within that:

% log show --debug --info --last 15m --predicate "category == 'violation' AND composedMessage MATCHES 'Sandbox: FontRequest.*deny.*' and NOT (composedMessage CONTAINS 'vfs')" system_logs.logarchive

Note I suppress log entries containing vfs because there’s a lot of them and I believe that they’re just noise.

I only see entries like this:

type: error
time: 2026-09-17 12:17:17.945576 +0200
process: kernel
subsystem: com.apple.sandbox.reporting
category: violation
message: Sandbox: FontRequest(1055) deny(1) iokit-open-user-client AppleNVMeEANUC

and I don’t believe that they’re relevant to this issue.

I was hoping to see an obvious sandbox violation which would then represent a starting point for further investigation. Without that, I’m a bit stuck.


perhaps you can give your opinion on the following workaround:

This approach is perfectly reasonable for your directly distributed app. It’s one of the designs I talk about in The Case for Sandboxing a Directly Distributed App.

The situation with the Mac App Store is trickier. It will certainly work, but I can’t offer any opinions as to what App Review will think about it.

should I use the iOS-style group identifier for this

That’s generally what I recommend, at least in the absence of some compelling reason to use a macOS-style one.


Taking a step back, the fact that this API has been deprecated since 10.6 11.0 with a note saying This functionality will be removed in a future release isn’t exactly encouraging |-:

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I was hoping to see an obvious sandbox violation

I couldn't see those either, that's why I filed a bug report. Thanks again for looking into it though!

The API has been deprecated since macOS 11, not 10.6. I understand that it may be removed in the future, but:

  1. There seems to be no alternative and many users (designers) depend on this functionality.
  2. The API still works fine for non-sandboxed apps. It appears that both requesting app and the listening app need to be non-sandboxed. So this indicates it's a sandboxing issue, not an API deprecation/removal issue.

I can’t offer any opinions as to what App Review will think about it.

Totally understand you're not part of App Review. Just curious: in the proposed workaround the sandboxed app submitted to the Mac App Store would only try to create an XPC connection to a mach service with the app group identifier (user opt in). My understanding was that this is allowed, due to the app group. The app is still fully sandboxed and the user can optionally download an external Helper.

You seem to imply that this XPC connection is not always allowed?

Referring to: https://developer.apple.com/documentation/bundleresources/entitlements/com.apple.security.application-groups "In macOS, use app groups to enable IPC communication between two sandboxed apps, or between a sandboxed app and a nonsandboxed app."

Of course an entitlement or sandbox fix would be much preferred. Hopefully an engineer can look at the report :)

The API has been deprecated since macOS 11, not 10.6

Sorry. I read it wrong. But that's still Big Sur. The oldest reasonable OS these days is Ventura.

many users (designers) depend on this functionality

What's the functionality? Why does your app need this function? How would you do whatever this functionality is on iOS?

Just curious: in the proposed workaround the sandboxed app submitted to the Mac App Store would only try to create an XPC connection to a mach service with the app group identifier (user opt in). My understanding was that this is allowed, due to the app group. The app is still fully sandboxed and the user can optionally download an external Helper.

Setting aside the App Review complications, that's a bit tricky. I tried to see if I could implement something like this in an app I'm developing. I could not get a sandboxed app to talk directly to a non-sandboxed launch agent, even if both were in the same app group. This was a technical limitation. If the launch agent is sandboxed, then it works. The launch agent can have a non-sandboxed XPC service.

But then you're back to App Review concerns. App Review certainly won't test this functionality. And that means you won't be able to mention it on the App Store or lead users to the external download. Yet you MUST mention it in the App Review notes. Otherwise, that's a risk of "hidden functionality", which can lean to full developer account termination action. And even if you make it through all that, you still have to explain it to the users.

The API has been deprecated since macOS 11, not 10.6.

Indeed. Sorry for the confusion. I’ve gone back and corrected my previous post.

You seem to imply that this XPC connection is not always allowed?

At a technical level, sandboxed apps are allowed to make IPC connections via an app group, regardless of whether the other end of the IPC connection is sandboxed or not. That’s what’s expected (per that doc you found) and it matches my experience.


I could not get a sandboxed app to talk directly to a non-sandboxed launch agent

I’m not sure why you had problems with this, but I’ve done this myself and it worked for me. I’ve also seen other developers take advantage of it. I’m happy to help either you or floorish investigate any problems you encounter with this.

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I’m not sure why you had problems with this, but I’ve done this myself and it worked for me.

Your relationship to these technologies and APIs is much different than mine. I will only ship, and recommend, those techniques that I can get to work.

It took me about 2 years, 1.5 apps, significant effort, and many attempts to get a sandboxed app to talk to a sandboxed launch agent via XPC. I have utterly no idea why I couldn't get it working at first. As far as I know, I'm not doing anything differently now. There must have been some subtle difference or bug, but I don't know what.

I just tried turning sandbox off on my launch agent on macOS 27 and it worked! So I guess I've continued to make subtle improvements. It will be a few days before I can test that on 13-26 and remove the XPC service.

This stuff ain't rocket science. In my experience, putting satellites in orbit is much easier than this.

I’ve made a note to fix this.

And it’s back!

Thanks again for letting me know.

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

It will be a few days before I can test that on 13-26 and remove the XPC service.

An unsandboxed launch agent contained in a sandboxed app does seem to work, with XPC, on versions 13, 15, and 27. Haven't tested the other versions.

I'm unaware of any specific change over the past two years to get sandboxed XPC working to this extent.

Obviously this isn't for the Mac App Store. But it will simplify things. Ironically enough, now I can get rid of a bunch of XPC.

CTFontManagerCreateFontRequestRunLoopSource does not receive events in macOS 27
 
 
Q