launchctl: Bootstrap failed: 5: Input/output error
2025-09-26
Categories: Programming
Initial symtoms
We have an internal service that needs to start a boot. The responsible team wrote a simple launchd script, like this:
1<?xml version="1.0" encoding="UTF-8"?> 2<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3<plist version="1.0"> 4<dict> 5 <key>Label</key> 6 <string>com.example.watchdog</string> 7 8 <key>ProgramArguments</key> 9 <array> 10 <string>/usr/local/bin/watchdog</string> 11 </array> 12 13 <key>RunAtLoad</key> 14 <true/> 15 16 <key>KeepAlive</key> 17 <true/> 18 19 <key>SessionCreate</key> 20 <true/> 21 22 <key>StandardOutPath</key> 23 <string>/var/log/watchdog.out</string> 24 25 <key>StandardErrorPath</key> 26 <string>/var/log/watchdog.err</string> 27</dict> 28</plist>
However, when trying to load it, we ran into this error:
1sudo launchctl bootstrap system /Library/LaunchDaemons/com.example.watchdog.plist 2Password: 3Bootstrap failed: 5: Input/output error
Interestingly, the same error also appears if the service is already running. But in this case, it wasn’t:
1sudo launchctl bootout system /Library/LaunchDaemons/com.example.watchdog.plist 2Boot-out failed: 5: Input/output error
To rule out issues with the binary itself, I tried starting it manually:
1/usr/local/bin/watchdog
It ran without problems, so the error cleary happens before the binary is executed.
Unfortunately, man launchctl
shows no option to enable debugging for bootstrap
, which makes troubleshooting trickier.
Narrowing down the cause
I then tried swapping the binary path in a known working launchd script with /usr/local/bin/watchdog
. The modified script looked like this:
1<?xml version="1.0" encoding="UTF-8"?> 2<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 3<plist version="1.0"> 4<dict> 5 <key>Crashed</key> 6 <true/> 7 <key>KeepAlive</key> 8 <true/> 9 <key>Label</key> 10 <string>org.openvpn.client</string> 11 <key>ProgramArguments</key> 12 <array> 13 <string>/usr/local/bin/watchdog</string> 14 </array> 15 <key>RunAtLoad</key> 16 <true/> 17 <key>SessionCreate</key> 18 <true/> 19 <key>StandardOutPath</key> 20 <string>/var/log/ovpnagent.log</string> 21</dict> 22</plist>
By removing keys one by one, I eventually found the culprit: the label value. If the label is set to com.example.watchdog
, the bootstrap failed. If I changed it to something else, it worked.
Root cause
It turned out the service had been accidentally disabled during earlier experiments with the .plist
.
Running:
1sudo launchctl print system
revealed this:
1disabled services = { 2 "com.example.watchdog" => disabled 3}
Fix
The solution is to re-enable the service and then bootstrap it again:
1sudo launchctl enable system/com.example.watchdog 2sudo launchctl bootstrap system /Library/LaunchDaemons/com.example.watchdog.plist
Related Posts:
- nnn: wcswidth returns different values for same Unicode code point between macOS and Linux
- How I setup a new Macbook in 2023
- Load averages approximately 1000 on macOS?
- Integration testing TUI applications in Rust
- libp2p performance benchmarking