53

I want to run a unison sync service running in the background whenever I login. But the status code of my agent is 78. I don't know why, I tried some fix posted online, but it just doesn't work.

What's the problem?? below is the plist file for my service.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>syncmyproject</string>
    <key>StandardOutPath</key>
    <string>/var/log/syncmyproject.log</string>
    <key>StandardErrorPath</key>
    <string>/var/log/syncmyproject.log</string>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>Debug</key>
    <true/>
    <key>EnableGlobbing</key>
    <true/>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/local/bin/unison</string>
      <string>-auto</string>
      <string>-batch</string>
      <string>-repeat watch</string>
      <string>~/home/project</string>
      <string>~/project</string>
    </array>
</dict>
</plist>
Aaron Shen
  • 8,124
  • 10
  • 44
  • 86
  • 7
    You can `grep` this file for possible clues as to what's wrong: `/var/log/system.log` – Nick Dec 01 '16 at 19:52

10 Answers10

63

I read man launchctl, find 78 means function not implemented. It doesn't help much.

Finally I make it work, actually there were errors in the plist, I recommend to install the brew install --cask launchcontrol, which is a gui tool for launchctl, it can help detect errors and trouble shooting.

Robin van Baalen
  • 3,632
  • 2
  • 21
  • 35
Aaron Shen
  • 8,124
  • 10
  • 44
  • 86
  • 8
    Thanks for this. launchcontrol helped solve my issue. For the record I had status 78 and my issue was that my script did not start with an interpreter e,g; `#!/bin/sh` – gooddadmike Feb 26 '16 at 14:37
  • 5
    For me the problem was, that the log directory was not accessible by the current user. – d4Rk Oct 25 '16 at 10:16
  • yep, me too. I had an error in the shebang. This made it difficult to debug since the script performed flawlessly when I executed it, but not when launchd tried to execute it. – wetjosh Dec 16 '16 at 17:45
  • launchcontrol was quite helpful! It costs money but the trial version can still catch errors, it just won't save the new plist file. One issue that caught me was that standard error output path was set to a path it couldn't write to. LaunchControl caught this and detected it while launchctl would only ever give me exist code 78! Also this website, http://www.launchd.info/, but the LaunchControl person has lots of useful troubleshooting info. It sort of plugs LaunchControl in a few places but is also useful by itself. – Chris Apr 24 '18 at 01:41
  • 1
    The issue in my case was the application targeted did not have execute permissions – Preston Sep 02 '18 at 03:33
  • 1
    An invalid `WorkingDirectory` can cause a status code of `78` as well. – EpicVoyage Apr 19 '19 at 11:38
  • for me the problem was clearly mentioned in /var/log/system.log that the script's permission is denied. chmod 755 was sufficient to get everything work. also note that if anything is added to PATH via a custom script added in bashrc or bash_profile that doesn't get executed as well so best to place your entire PATH as EnvironmentVariables list in the plist file. – Praveen Tiwari May 27 '19 at 04:09
  • launchcontrol helped with this. i created an app from a shell script using Automator and i needed to update the path in plist to target the executable Application Stup, not the application folder. – commbot Apr 01 '20 at 09:05
  • LaunchControl is trial software, forget about it. – Adrian Maire Nov 25 '20 at 12:31
  • If I enter ```launchctl list``` in terminal I see my launchd job showing 78. However if I load up LaunchControl, I cannot see my job, am I doing something wrong? I've used the dropdown with the system agents / daemon agents & all the others but it is not there. Also, where to put ```#!/bin/sh```? – atreeon Jun 02 '21 at 12:55
  • 1
    These days it's `brew install --cask launchcontrol` for anyone stumbling upon this answer. I've submitted an edit as well. – Robin van Baalen Jan 11 '22 at 20:41
  • @AdrianMaire however, the trial version helped me to find the issue. In my case I was trying to launch an application bundle (.app). LaunchControl also provided the solution which is to use */usr/bin/open*. – Osama Apr 01 '22 at 14:56
  • To learn what an error code means, simply run `launchctl error my_err_code` – BallpointBen May 17 '22 at 01:30
16

I found the error had to do with permissions. I was trying to redirect errors and logs to the /var/log directory which my user is not able to write to. Changing the path to something where my user had proper permissions to r+w fixed it.

Also, be careful when loading your LaunchAgents. Do not use sudo to load a plist if you are in the ~/Library/LaunchAgents directory.

Brian McCall
  • 1,831
  • 1
  • 18
  • 33
  • 2
    Holy smokes, that was my error too! Changing the logs to a different folder fixes it. – Matt Jun 03 '18 at 03:55
  • 2
    "Be careful when loading your LaunchAgents. Do not use sudo to load a plist if you are in the ~/Library/LaunchAgents directory." Oh my holy goat. This... You are my hero. – c4sh Jun 20 '18 at 15:33
12

To view a description of all error codes, type

launchctl error <insert numerical error code here>

e.g.:

% launchctl error 77 77: No locks available

lobi
  • 344
  • 1
  • 4
  • 16
7

[Ran into this problem as well, so documenting what I've found]

"78" is the last exit code of the job you're running. From man launchctl:

With no arguments, list all of the jobs loaded into launchd in three columns. The first column displays the PID of the job if it is run- ning. The second column displays the last exit status of the job. If the number in this column is negative, it represents the negative of the signal which stopped the job. Thus, "-15" would indicate that the job was terminated with SIGTERM. The third column is the job's label. If [label] is specified, prints information about the requested job.

I.e. you need to read the documentation (or source code) for whatever job you're starting. (In my case, mysqld)

It's worth noting that "78" is mentioned as a standard exit code on Linux, indicating a configuration error. So take a look at your job configuration (and error logs?) to see if you have something misconfigured.

broofa
  • 37,461
  • 11
  • 73
  • 73
  • 2
    in my case I had forgotten to chmod +x the shell script ':) – Edoardo Sep 16 '17 at 15:26
  • In my case, the log rotator (newsyslog) wasn't configured to restore the previous owner of the stdout and stderr files, rendering them unwritable to the current user. – JamesKingston May 01 '19 at 05:12
  • my 5 cent is to use `/tmp/demo.stderr*` as `StandardErrorPath` value in `non-root` user mode, but `Console.app` log does not complain anything about permission.Delete those `Standard*Path` values in plist make my service pid status return to 0. – zionpi Jul 31 '20 at 09:21
4

Here's what caught me: In Mac OS X you can run shell-scripts from command-line even if there's "just the script" in the file. However, when you run them from launchd you have to tell which binary that should run the script. A suppose that when you run from command-line it just uses the shell you are currently in (in my case bash), but when running from launchd there is no "surrounding script". I added

#!/bin/sh

as the first line in the script file, and then it worked.

Dan Bergh Johnsson
  • 964
  • 10
  • 14
  • Also I had comments as file header before `#!`, which cause the error. The script should not have any comments before `#!`. – panc Dec 06 '20 at 03:12
  • @dan-bergh-johnsson can you tell me exactly where to put the ```#!/bin/sh``` please? Could you please put an example? Thank you – atreeon Jun 02 '21 at 13:00
  • 1
    @atreeon The `#!/bin/sh` must be at the exact beginning of the file. On the first line, not indented. In fact, `#` and `!` must be the first two bytes of the file on disk. – Gordon Davisson Aug 08 '22 at 19:32
3

In my case, script in <ProgramArguments> is not executable and thus get 78 function not implemented.

PodBlood
  • 179
  • 1
  • 10
  • This was my issue. Upgraded to Catalina and everything stopped working code 78! Was because Catalina `chmod 700 ~/Documents` without me knowing. – Sukima Feb 05 '21 at 14:59
  • I can't up vote this enough. You saved me :pray: :bow: – Sukima Feb 05 '21 at 15:05
2

Similar to above I was getting a status 78 because I had symlink in my script path. The fix was to use the absolute path.

Cephos
  • 352
  • 1
  • 2
  • 9
1

I got this error while trying to run mono to start a local webserver. Turns out the fix was to not use the mono path given by "which mono" (which is a symlink: /Library/Frameworks/Mono.framework/Versions/Current/Commands/mono) but the actual location of the exe (in my case /Library/Frameworks/Mono.framework/Commands/mono).

ra00l
  • 570
  • 4
  • 20
0

I'm keeping getting 78 code for the sake of xml format issue:

At first, My emacs auto reformat my xml like this:

<?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">
  <dict>
    <key>Label</key>
    <string>user.eric.g.autosyncdropbox.agent</string>
    <key>ProgramArguments</key>
    <array>
      <string>/Users/eric/G/bin/fswatchG.sh</string>
    </array>
    <key>KeepAlive</key>
    <true />
    <key>StandardOutPath</key>
    <string>
    /Users/eric/.tmp/user.eric.g.autosyncdropbox.out.log</string>
    <key>StandardErrorPath</key>
    <string>
    /Users/eric/.tmp/user.eric.g.autosyncdropbox.error.log</string>
  </dict>
</plist>

And I was not able to find these two line is returned...

    <string>
    /Users/eric/.tmp/user.eric.g.autosyncdropbox.out.log</string>
    <key>StandardErrorPath</key>
    <string>
    /Users/eric/.tmp/user.eric.g.autosyncdropbox.error.log</string>

That was sucks, and absolutely a waste of life...

Eric
  • 295
  • 3
  • 6
0

I was chasing for the status 78 error for a long time.

My LaunchDamon could be started by hand with status 0 , but after a system reboot it has the status 78. Sometimes the daemon was running, sometimes it was not.

Using the app LaunchControl ( which is great btw.) didn't help in this case. There was no output in the standard out and err files.

I could solve the problem by adding a KeepAlive condition to the daemons plist file, referencing a mounted file system where the daemon executable resides.

<key>KeepAlive</key>
<dict>
    <key>PathState</key>
    <dict>
    <key>/Volumes/MountedFileSystem</key>
    <true/>
    </dict>
</dict>

I hope this tip might help someone.

hjbflyer
  • 67
  • 8