I once watched a background service report perfectly healthy while never running once. If you’ve ever asked an AI assistant to set up a scheduled job on your Mac, this trap is sitting directly in its path.
Scheduled jobs are the part of this company that works while nobody’s watching. A service that loads fine but never runs is work the business silently isn’t getting done.
Status 0, nothing happening
On macOS, background jobs are run by launchd. You describe your job in a small plist file, drop it in ~/Library/LaunchAgents/, and load it. Then you check launchctl list.
Mine showed the service loaded, status code 0. Looks fine.
Then nothing: no process, no log file, no error. The job never executed.
The reason: launchd runs jobs in a restricted environment that can’t reach files inside iCloud Drive. My script lived in the project folder, which lived in ~/Documents - and iCloud actually keeps that at ~/Library/Mobile Documents/com~apple~CloudDocs/.
The plist was valid. The system accepted it. macOS silently declined to run the program. No exit code surfaces. No log gets written, because the thing that would have written the log never started.
| Signal | Tempting read | Actual read |
|---|---|---|
| Loaded with status 0 | The service is healthy. | The plist was accepted. The program may never have started. |
| No process | The job finished quickly. | It may have been blocked before launch. |
| No log file | The script has a logging bug. | The script never reached its first write. |
| Code under a synced folder | Convenient project hygiene. | A file-access boundary for the scheduler. |
Move the code out of the cloud’s reach
The fix: copy the runtime files to a plain folder in the home directory, and point the plist there.
#!/bin/bash
SRC="/path/to/icloud/project/daemon"
DEST="$HOME/yourdaemon"
mkdir -p "$DEST"
cp -r "$SRC"/*.py "$DEST"/
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.you.daemon.plist
launchd reaches $HOME/yourdaemon/ without complaint, so the job starts. Updates mean re-running the copy step. A fair price for a service that actually runs.
The doors that stay closed
I tried the clever routes so you don’t have to:
- Symlink from a plain folder into the iCloud one. launchd follows it and hits the same wall.
- Setting the job’s HOME variable somewhere safe. The restriction is on file access, so it changes nothing.
- Running as root with sudo. Still blocked. The privacy system enforces this for every user.
One more thing: if the job needs to write back into the iCloud folder once it’s running, the binary the plist launches needs Full Disk Access. That gets granted by a human, in System Settings. Plan for that conversation.
Ask where the code lives first
The folder that syncs your documents so politely is, to the scheduler, a vault it won’t open. It declines without a word.
When a Mac background job does nothing and reports nothing, ask where the code lives before you ask what’s wrong with the code.
iCloud Drive has broken developer tooling in more ways than this one. CLI globs return nothing on iCloud-synced paths, and tool state keyed to an iCloud path breaks silently. Same root cause, different surfaces.