How to debug a user LaunchAgent that doesn’t seem to start or load with launchctl

launchdplist

Problem Description

Running the following user LaunchAgent does not show a started job, nor does the job log an error or do anything detectable. The Vault commands embedded in the plist file work fine when run from a user crontab or the command line, though. I've run the following commands as a non-root user:

# returns exit status 3
launchctl start local.localhost.RenewVaultToken.plist
echo $?

# also returns exit status 3
launchctl enable gui/$UID/local.localhost.RenewVaultToken
launchctl start gui/$UID/local.localhost.RenewVaultToken
echo $?

# returns "Load failed: 5: Input/output error"
launchctl load gui/$UID/local.localhost.RenewVaultToken

# no results
launchctl list | fgrep -i vault

Tailing the system log doesn't show anything identifiable, nor are any log files created. As far as I can tell, the job can't/won't start or run, but I'm not sure how to effectively debug it further.

LaunchAgent File Contents

I have the following file stored in ~/Library/LaunchAgents with the filename local.localhost.RenewVaultToken.plist. The file is set to mode 0600.

<?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">

<!-- ~/Library/LaunchAgents/local.localhost.RenewVaultToken.plist -->
<plist version="1.0">
    <dict>
        <key>Label</key>
        <string>local.localhost.RenewVaultToken</string>

        <key>ProgramArguments</key>
        <array>
            <string>/usr/local/bin/vault</string>
            <string>token</string>
            <string>renew</string>
            <string>-increment=12h</string>
            <string>-address="https://vault.example.com"</string>
        </array>

        <key>StartInterval</key>
        <integer>14400</integer>

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

        <key>Debug</key>
        <true/>

        <key>StandardOutPath</key>
        <string>/Users/foo/stdout.log</string>

        <key>StandardErrorPath</key>
        <string>/Users/foo/stderr.log</string>
    </dict>
</plist>

Best Answer

I had this too, and I think I have a solution.

I read through the launchctl man pages and saw that load and start are now considered legacy subcommands.

Subcommands from the previous implementation of launchd are generally available, though some may be unimplemented.

I think the old behaviour can be achieved by the following two commands:

# Enable this plist
launchctl enable service-target

# Run this plist now
launchctl kickstart service-target

The service-target that worked for me was in the form gui/$UID/myPlistFilename

The plist filename didn't include the .plist on the end.

So, for the file at ~/Library/LaunchAgents/setUserKeyMapping.plist I ran:

launchctl enable gui/$UID/setUserKeyMapping
launchctl kickstart gui/$UID/setUserKeyMapping

If you pass -kp to the kickstart action, it will kill any running instance and restart it, then print out the PID of the new instance.

launchctl kickstart -kp gui/$UID/setUserKeyMapping