Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

LaunchAgent can't connect to CloudKit daemon

For this code:

let status = try await container.accountStatus()

Seeing this error:

2025-05-08 15:32:00.945731-0500 localhost myAgent[2661]: (myDaemon.debug.dylib) [com.myDaemon.cli:networking] Error Domain=CKErrorDomain Code=6 "Error connecting to CloudKit daemon. This could happen for many reasons, for example a daemon exit, a device reboot, a race with the connection inactivity monitor, invalid entitlements, and more. Check the logs around this time to investigate the cause of this error." UserInfo={NSLocalizedDescription=Error connecting to CloudKit daemon. This could happen for many reasons, for example a daemon exit, a device reboot, a race with the connection inactivity monitor, invalid entitlements, and more. Check the logs around this time to investigate the cause of this error., CKRetryAfter=5, CKErrorDescription=Error connecting to CloudKit daemon. This could happen for many reasons, for example a daemon exit, a device reboot, a race with the connection inactivity monitor, invalid entitlements, and more. Check the logs around this time to investigate the cause of this error., NSUnderlyingError=0x600001bfc270 {Error Domain=NSCocoaErrorDomain Code=4099 UserInfo={NSDebugDescription=

I initially started the this process as System Daemon to see what would happen (which obviously does not have CloudKit features). Then moved it back to /Library/LaunchAgents/ and can't get rid of that error.

I see also following message from CloudKit daemon:

Ignoring failed attempt to get container proxy for <private>: Error Domain=NSCocoaErrorDomain Code=4099 UserInfo={NSDebugDescription=<private>}
Automatically retrying getting container proxy due to error for <private>: Error Domain=NSCocoaErrorDomain Code=4099 UserInfo={NSDebugDescription=<private>}
XPC connection interrupted for <private>

And this error for xpc service:

[0x130e074b0] failed to do a bootstrap look-up: xpc_error=[3: No such process]

If I start the same cli process directly from XCode, then it works just fine.

Answered by DTS Engineer in 839596022

Ziqiao and I had a long conversation about this with our CloudKit engineering colleague, and our conclusion in that it’s likely that there’s a way to make this work.

A launchd agent runs in a user context and thus generally has access to user state.

IMPORTANT This is different from a launchd daemon, which runs in a global context. We don’t have a supported path forward for using CloudKit from a daemon.

The agent controls the specific contexts it runs in via its LimitLoadToSessionType property. This defaults to Aqua, meaning that the agent runs in GUI login contexts. An agent in that context should be able to use CloudKit.

We suspect you’re having problems because your agent is a standalone executable. That has two issue:

  • It has no bundle ID.

  • CloudKit is gated by a restricted entitlement, one that needs to be authorised by a provisioning profile. With a standalone executable there’s nowhere to put that profile.

You can get around the first point by embedding an Info.plist in your executable, but that won’t help with the second. The only way around the second is to put your agent in an app-like wrapper. For instructions on how to set that up, see Signing a daemon with a restricted entitlement. Once you do this, you’ll have to change the path in your launchd.plist to point to the executable within the bundle, rather than to the bundle itself.

IMPORTANT The overall wrapping mechanism described in Signing a daemon with a restricted entitlement works for both daemons and agents. However, to reiterate, this won’t work for a daemon in the CloudKit case, because CloudKit requires a user context.

For more about provisioning profiles, see TN3125 Inside Code Signing: Provisioning Profiles. For more about structuring your bundle, see Placing Content in a Bundle.

Share and Enjoy

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

From the information you've provided you've correctly identified the issue, your LaunchAgent isn't properly sandboxed to communicate with the CloudKit service. In general CloudKit is only supported from within an Application like process.

Ziqiao and I had a long conversation about this with our CloudKit engineering colleague, and our conclusion in that it’s likely that there’s a way to make this work.

A launchd agent runs in a user context and thus generally has access to user state.

IMPORTANT This is different from a launchd daemon, which runs in a global context. We don’t have a supported path forward for using CloudKit from a daemon.

The agent controls the specific contexts it runs in via its LimitLoadToSessionType property. This defaults to Aqua, meaning that the agent runs in GUI login contexts. An agent in that context should be able to use CloudKit.

We suspect you’re having problems because your agent is a standalone executable. That has two issue:

  • It has no bundle ID.

  • CloudKit is gated by a restricted entitlement, one that needs to be authorised by a provisioning profile. With a standalone executable there’s nowhere to put that profile.

You can get around the first point by embedding an Info.plist in your executable, but that won’t help with the second. The only way around the second is to put your agent in an app-like wrapper. For instructions on how to set that up, see Signing a daemon with a restricted entitlement. Once you do this, you’ll have to change the path in your launchd.plist to point to the executable within the bundle, rather than to the bundle itself.

IMPORTANT The overall wrapping mechanism described in Signing a daemon with a restricted entitlement works for both daemons and agents. However, to reiterate, this won’t work for a daemon in the CloudKit case, because CloudKit requires a user context.

For more about provisioning profiles, see TN3125 Inside Code Signing: Provisioning Profiles. For more about structuring your bundle, see Placing Content in a Bundle.

Share and Enjoy

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

It’s better to reply as a reply, rather than in the comments; see Quinn’s Top Ten DevForums Tips for this and other titbits.

if I simply put it in /Library/LaunchAgents then cloudkit does not work.

That’s strange. In the launchd architecture there’s no difference between a job loaded from ~/Library/LaunchAgents and a job that’s loaded from /Library/LaunchAgents. The latter just acts like the job was loaded from the former for all users.

So, to confirm:

  • You have no LimitLoadToSessionType property in the job’s property list.

  • Your agent is packaged in an app-like wrapper.

  • Your agent executable is the main executable for that bundle.

  • Your property list has Program property (or ProgramArguments property) that points to that executable.

Is that correct?

Share and Enjoy

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

LaunchAgent can't connect to CloudKit daemon
 
 
Q