How to start a service using Mac OSX's launchctl

Update June 2020

I created a cross-platform tool to handle creating launchd and systemd service files:

  • serviceman

Using launchd

launchd can easily get into "weird" states.

  • load means to read the config file and potentially schedule a launch.
  • unload means to stop and unschedule the config file
  • start will start the service (ignoring the schedule, I believe)
  • stop will stop the service (again, ignoring the schedule)

Generally if you want to "restart" it you unload and reload the config like this:

launchctl unload -w ~/Library/LaunchAgents/com.apple.myservice.plist
launchctl load -w ~/Library/LaunchAgents/com.apple.myservice.plist

The -w means "write" which means that the change will affect reboots (will load every login or boot... or will not load ever again at login or boot).

If it's a system-level service (in /Library/LaunchDaemons or /Library/LaunchAgents you may need to do it with sudo (and if you did it without sudo by mistake, you may need to unload it without sudo and then reload it with sudo)

The key in a file that causes it to start on load is RunAtLoad (and KeepAlive keeps it running if it dies for some reason)

<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>

It's sometimes tricky to get debug logging from launchctl itself, but the keys StandardErrorPath and StandardOutPath can at least help you know if your application is dying due to missing or bad information (an unexpanded environment variable or non-writable path, for example). Just be sure that the path you specify is writable by the user running the process.

<key>StandardErrorPath</key>
<string>/tmp/appname-error.log</string>
<key>StandardOutPath</key>
<string>/tmp/appname-info.log</string>

Because they're so hard to debug, I'd recommend using LaunchControl or launched and mix that with a healthy reading of launchd.info.

Also, there are a number of debugging hints here: https://serverfault.com/questions/183589/how-do-i-activate-launchd-logging-on-os-x

I haven't tried it yet myself, but this solution looks the simplest:

sudo launchctl log level debug 
tail -f /var/log/system.log

I ran into similar problems today.

Simply unload the service and load it again solves the File exists problem.

It looks like every time you update a plist file you're gonna have to do that.