I wanted to write a simple launchd job that runs a script every Monday morning at 7:00 am. The goal is to pull an image from tapmusic.net that catalogs my last.fm listening habits from the prior week. The daemon runs properly and is able to execute the script just fine, and the script does exactly what I want it to. The issue is that the job is being executed every day at midnight, not Monday at 7. This is my first time trying out something like this, and I tried to follow templates on developer.apple.com and ones floating around the net, but I'm really unsure of how I can fix this problem. Here is the *.plist file that I'm running:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">

Like I said, I've been able to load and run the job just fine, just not at the right time.

Also, my system.log file is getting bombarded by a message and looks like this:

Jun 15 08:54:46 ***-MBP com.apple.xpc.launchd[1] (local.lastfm_chart): Service only ran for 2 seconds. Pushing respawn out by 8 seconds.
Jun 15 08:54:57 ***-MBP com.apple.xpc.launchd[1] (local.lastfm_chart): Service only ran for 3 seconds. Pushing respawn out by 7 seconds.
Jun 15 08:55:07 ***-MBP com.apple.xpc.launchd[1] (local.lastfm_chart): Service only ran for 2 seconds. Pushing respawn out by 8 seconds.
Jun 15 08:55:45 --- last message repeated 2 times ---
Jun 15 08:55:45 ***-MBP com.apple.xpc.launchd[1] (local.lastfm_chart): Service only ran for 8 seconds. Pushing respawn out by 2 seconds.
Jun 15 08:55:50 ***-MBP com.apple.xpc.launchd[1] (local.lastfm_chart): Service only ran for 2 seconds. Pushing respawn out by 8 seconds.
Jun 15 08:56:12 --- last message repeated 1 time ---
Jun 15 08:56:12 ***-MBP com.apple.xpc.launchd[1] (local.lastfm_chart): Service only ran for 3 seconds. Pushing respawn out by 7 seconds.
Jun 15 08:56:34 --- last message repeated 1 time ---
Jun 15 08:56:34 ***-MBP com.apple.xpc.launchd[1] (local.lastfm_chart): Service only ran for 4 seconds. Pushing respawn out by 6 seconds.
Jun 15 08:56:43 ***-MBP com.apple.xpc.launchd[1] (local.lastfm_chart): Service only ran for 2 seconds. Pushing respawn out by 8 seconds.
Jun 15 08:57:07 --- last message repeated 1 time ---
Jun 15 08:57:07 ***-MBP com.apple.xpc.launchd[1] (local.lastfm_chart): Service only ran for 5 seconds. Pushing respawn out by 5 seconds.
Jun 15 08:57:15 ***-MBP com.apple.xpc.launchd[1] (local.lastfm_chart): Service only ran for 3 seconds. Pushing respawn out by 7 seconds.
Jun 15 08:57:25 ***-MBP com.apple.xpc.launchd[1] (local.lastfm_chart): Service only ran for 2 seconds. Pushing respawn out by 8 seconds.

I'm not sure what this signifies, either.

I'm on mojave 10.14.6, if that matters.

Adding an edit to include the bash script that is being executed:


now=`date -v -7d +"%Y-%m-%d"`
curl "https://tapmusic.net/collage.php?user=gas_giant&type=7day&size=4x4&caption=true" -o /Users/****/Documents/Music/last.fm\ Listening\ Reports/tuneage_${now}.jpg
  • And you are confident that your shell script is executing properly ? If you specify a key value for stderr, you can see if any errors are occurring during execution. – CJK Jun 15 '20 at 13:59
  • Hi, welcome to Ask Different. Your file looks OK, so the script may be the culprit. If you replace the StartCalendarInterval key with <key>RunAtLoad</key><true/>, does the script run or do you see the same behavior? Can you add StandardErrorPath and StandardOutPath keys to log errors and output (see man launchd.plist for details) and share any findings? – jaume Jun 15 '20 at 14:01
  • 1
    @CJK @jaume Thanks for your answers. Everything works how it should when I replace StartCalendarInterval with <key>RunAtLoad</key><true/>. Adding in StandardErrorPath produces the same output as when I run the script itself, and adding in StandardOutPath produces an empty .log file. That seems backwards but seems to be ok. I've edited my original post to include the bash script I'm using as well. – coffeetrick Jun 15 '20 at 14:50
  • Thank you for testing, that's interesting. Could it be that the network was down or the website wasn't reachable at 07:00? For further troubleshooting, I'd suggest that you add an if block to wrap the curl command like this: if nc -z tapmusic.net 443 > /dev/null 2>&1; then curl ...; else echo "Aborting: website not reachable" >&2; fi and leave the StandardErrorPath key in place to catch any errors. Could you schedule it for tomorrow and share the result? – jaume Jun 15 '20 at 15:54
  • @jaume I've had the launchd job running since early April and never had a problem with connecting to the website, so I don't think that's the issue. Since things have been functioning well enough and I can still get the image that I'm looking for I haven't tried to really solve the problem until now. Looking back, the original image that was grabbed by the job was created at 7:00 am but was modified at the following midnight. Every image since then has been grabbed at midnight and then modified at the following midnight. I'm not sure what to make of that. – coffeetrick Jun 15 '20 at 16:57

From your log it looks like you are running as a daemon, not an agent. A daemon is meant to run constantly, while an agent only once.

So your .plist file should be in ~/Library/LaunchAgents. Once it is in that directory then you still have to load it using launchctl load <filename>.

I'm also wondering if you have a leftover process from a previous attempt as the log looks like you have KeepAlive set but not the .plist. That's why the mention of respawn.

Next, I was wondering about the script path - is the absolute path actually /scripts/lastfm.sh. If you are using the Program key rather than the ProgramArguments key it has to be an absolute path.

Assuming that you have not loaded into System space but correctly into your user space then I'd start by having a look at what launchctl thinks is happening behind the scenes.

  1. Find out your user ID by running id -u (mine is 502)
  2. List the information for your job launchctl print gui/502/local.lastfm_chart

This will include an event triggers section that should show you exactly when launchctl thinks it should run the command. It will also show you the command, if keepalive is set and other useful information.

Oh, and keep out the RunAtLoad unless you actually want to RunAtLoad. The best way to test things is to give it a kickstart - launchctl kickstart gui/502/local.lastfm_chart will run your service.

The same is true with StandardErrorPath and StandardOutPath - rather than constantly changing the .plist file you can use the launchctl debug command to alter these once before you kickstart, so:

  1. launchctl debug gui/502/local.lastfm_chart —-stdout —-stderr will set stdout and stderr to your terminal session for the next invocation of the service.
  2. launchctl kickstart gui/502/local.lastfm_chart runs it with those settings and then they disappear.
  • Thank you very much for this thorough answer! I had been loading this as a daemon, but I'll move it to ~/Library/LaunchAgents and load it from there. I noticed something odd with the daemon: if I set the StartCalendarInterval data to be a few minutes in the future, it would run only once at the specified time and the respawn issue didn't appear in system.log. But, running launchctl print system/local.lastfm_chart showed that the event triggers section was always tied to the StartCalendarInterval of 7 am Monday. I must have messed something up when I tried to update and reload it. – coffeetrick Jun 16 '20 at 23:18
  • Sorry for the double comment, but I want to provide some more info. I unloaded and deleted the file /Library/LaunchDaemons/local.lastfm_chart.plist and moved it to ~/Library/LaunchAgents/local.lastfm_chart.plist and then restarted my computer. Now running launchctl print system/local.lastfm_chart returns Could not find service "local.lastfm_chart" in domain for system and launchctl print gui/501/local.lastfm_chart returns info that changes with contents of the .plist file. I think you've solved my problem, but I'll set it for tomorrow morning to double check. Thanks again! – coffeetrick Jun 16 '20 at 23:53

Your Calendar Interval looks upside down. Start with the day and then the time. It should look like this:


You also don’t want the “Run At Load” value set because it will execute the script the moment the plist is loaded like at boot time or upon login.

As far as your script goes it looks fine. There’s nothing in there that will trigger it to run at a particular time as the date function is only being used to populate a variable that’s used in a filename.

  • According to my tests and this document at Apple: developer.apple.com/library/archive/documentation/MacOSX/…, key order doesn't seem to be relevant, or am I missing something? – jaume Jun 15 '20 at 15:57
  • @Allan I've played around with the order and had it in that exact configuration before; it didn't solve the problem. I put in RunAtLoad solely to test functionality; normally it's not included. And yep, the date function is just there to set the filename for the previous Monday to indicate the week during which I listened to the music. Thanks for your answer. – coffeetrick Jun 15 '20 at 16:15
  • Is your computer asleep at that time? – Allan Jun 15 '20 at 16:23
  • It is not. I have some things I use my computer for that require it to be on and active almost all of the time, so I've set it to prevent sleep when the display is off and disabled the put hard disks to sleep when possible option. – coffeetrick Jun 15 '20 at 16:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .