-
-
Notifications
You must be signed in to change notification settings - Fork 6
macOS Troubleshooting
Check the daemon logs before anything else, they usually tell you what's wrong. For Linux, see Linux Troubleshooting instead.
The launchd job redirects the daemon's stdout and stderr straight to a log file:
tail -100 /var/log/zentune.logFor a live stream:
tail -f /var/log/zentune.logEvery preset apply is logged with its trigger:
Applied preset 'Eco' (power source changed from AC to battery).
Applied preset 'Gaming' (selected in the app).
Applied preset 'Balance' (restoring saved settings at startup).
For more detail, enable debug logging (toggle Debug in Settings, or edit config directly):
# Assets/config.ini
[Settings]
debug = 1Then restart the daemon:
sudo launchctl kickstart -k system/com.horizonunix.zentuneCheck the job status:
sudo launchctl print system/com.horizonunix.zentuneLook for state = running. If the job isn't loaded at all:
sudo launchctl bootstrap system /Library/LaunchDaemons/com.horizonunix.zentune.plistIf there's no plist at /Library/LaunchDaemons/com.horizonunix.zentune.plist yet, the daemon was never installed, launch zentune and use Install / enable daemon in the setup wizard, or from the Settings tab.
You can also start the daemon by hand (needs root), useful for seeing errors directly:
sudo /opt/zentune/venv/bin/python3 /opt/zentune/src/Assets/daemon/daemon.py| Log message | Fix |
|---|---|
No SMU access path is available. |
Neither DirectHW nor the kext-free fallback is usable, see the backend section below |
Another daemon instance is already running (lock: /var/run/zentune_daemon.lock). |
A previous daemon instance is still running. Kill it: sudo pkill -f daemon.py
|
Cannot bind IPC socket ipc:///var/run/zentune.sock: |
The socket may be stale or held by another process. Run sudo rm /var/run/zentune.sock then restart the service |
Cannot remove stale socket /var/run/zentune.sock: |
Permission problem on the socket file. Run sudo rm /var/run/zentune.sock then restart the service |
Usually happens after an update where the daemon wasn't restarted. Fix:
sudo launchctl kickstart -k system/com.horizonunix.zentuneCheck /var/log/zentune.log. If you see Cannot bind IPC socket or Cannot remove stale socket:
sudo rm /var/run/zentune.sock
sudo launchctl kickstart -k system/com.horizonunix.zentunePython tracebacks mean something is broken in the install. Quickest fix:
curl -fsSL https://raw.githubusercontent.com/HorizonUnix/ZenTune/main/install.sh | bashThe launchd job has KeepAlive: SuccessfulExit = false, so it relaunches whenever the daemon exits with an error, same idea as systemd's Restart=on-failure on Linux. Check /var/log/zentune.log to see why it's crashing, the fix depends on the error.
To stop the restart loop and see daemon output directly:
sudo launchctl bootout system/com.horizonunix.zentune
sudo /opt/zentune/venv/bin/python3 /opt/zentune/src/Assets/daemon/daemon.pyCheck the socket exists:
ls -la /var/run/zentune.sockIf it's missing, the daemon isn't fully started yet, wait a few seconds.
If it exists but the TUI still can't connect, check permissions. Should be world-writable (daemon sets 666 on it at startup):
stat /var/run/zentune.sockNote
See macOS Installation for the full DirectHW / IOPCIBridge setup steps. This section is for when the daemon can't find either path, or picks the one you didn't expect.
Neither DirectHW nor the kext-free fallback is usable. Check which one you're missing:
kextstat | grep DirectHW # is the kext loaded?
sysctl kern.bootargs # does it include debug=0x144?If neither is true, install DirectHW (see macOS Installation §2) or add the debug=0x144 boot-arg and reboot (§3).
Check SIP allows kexts:
nvram csr-active-configShould be %00%08%00%00 (03080000). If not, fix it in your bootloader's SIP settings and reboot.
Expected. The IOPCIBridge fallback reaches config space only, it can't map physical memory for the PM table. Install DirectHW if you want the live sensor graphs.
DirectHW is only used if the kext is actually loaded (kextstat | grep DirectHW). If it's installed but not loaded, load it per the project's own instructions, then restart the daemon.
ZenTune detects your CPU without dmidecode or any external tool. On macOS it reads the CPUID sysctls directly:
sysctl machdep.cpu.family machdep.cpu.model machdep.cpu.brand_stringThese come straight from the CPUID instruction, so they're accurate even on a Hackintosh where SMBIOS is spoofed.
CPU was detected but has no SMU command table. Could be: CPU is pre-Zen 1, or too new to be added yet.
Try Settings -> Re-detect hardware first. If still Unknown, check the sysctl output above and file a bug with it plus your CPU model name.
Run Settings -> Re-detect hardware. If the wrong codename persists, it's a bug in detection logic, file a bug with your CPU model and the sysctl output above.
If you just want to pick a different premade preset table without fixing detection, use Settings -> Edit CPU info instead, see Configuration.
Something else may be resetting the power limits. Enable Reapply in Settings with a short interval:
Settings (7) -> Reapply preset periodically on -> Reapply interval = 3
The SMU loses state on sleep. Set a resume preset:
Automations (4) -> Preset on System Resume -> pick a preset
The daemon detects wake by comparing wall-clock time (which keeps advancing through sleep) against a monotonic clock (which doesn't), so a gap between them means the machine just woke up. You'll see Applied preset 'Balance' (woke from suspend after ~28m). in the logs.
If the resume preset never applies, enable Apply preset on daemon start in Settings as a fallback.
At least one of Preset on Battery Charge or Preset on Battery Discharge needs to be set. There's no separate on/off switch.
Check the daemon is running:
sudo launchctl print system/com.horizonunix.zentune | grep stateCheck power source:
pmset -g battOpen the Status tab (6) and check for rejected commands (marked [!]). Other possibilities: the CPU is throttling for thermal or VRM reasons, or your CPU family doesn't support a parameter, lines like some-arg -> not supported on HawkPoint in the apply output mean exactly that.
The editor only shows sections for parameters the CPU's SMU firmware supports. The System section (power profile, ASUS modes, CCD affinity) never appears on macOS since it reads Linux-only interfaces (/sys, asus-wmi, systemd), that's expected, see Custom Presets.
Check detected family:
grep -i family /opt/zentune/src/Assets/config.iniIf Unknown or wrong, fix detection first. If correct but sections are still missing, it's a genuine limitation of that CPU's SMU firmware.
The Info section in config.ini is missing or incomplete, usually after a bad update, manual config editing that removed required keys, or a first run that got interrupted. Let the wizard run to completion and don't skip hardware detection; Info only gets written when detection finishes.
If you hit Reset all in Settings, that's intentional. If it happened on its own, the Info section was broken and the wizard reset the config.
Custom presets live in Assets/custom.json. Updates back it up to /opt/zentune/custom.json.bak, restore with:
cp /opt/zentune/custom.json.bak /opt/zentune/src/Assets/custom.jsonCheck Assets/ is writable by the user running the TUI:
ls -la /opt/zentune/src/Assets/The install script chowns /opt/zentune to your user. If you installed manually with sudo, fix it:
sudo chown -R "$USER" /opt/zentune/srcSame as Linux, terminal must be at least 50x25, UTF-8 locale, and a real interactive terminal (no piping, no non-interactive shells). See the Linux Troubleshooting display section for the exact checks; they apply unchanged on macOS.
The plist bakes in absolute paths at install time. If you moved the app, the paths go stale. Launch the TUI once, it detects the mismatch, asks for your password, and rewrites the plist automatically:
zentuneIf that doesn't work, regenerate manually:
sudo launchctl bootout system/com.horizonunix.zentune
sudo tee /Library/LaunchDaemons/com.horizonunix.zentune.plist > /dev/null << 'EOF'
<?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>com.horizonunix.zentune</string>
<key>ProgramArguments</key>
<array>
<string>/opt/zentune/venv/bin/python3</string>
<string>/opt/zentune/src/Assets/daemon/daemon.py</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
</dict>
<key>StandardOutPath</key>
<string>/var/log/zentune.log</string>
<key>StandardErrorPath</key>
<string>/var/log/zentune.log</string>
</dict>
</plist>
EOF
sudo chown root:wheel /Library/LaunchDaemons/com.horizonunix.zentune.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/com.horizonunix.zentune.plistThe updater uses sudo mv internally to back up and swap the install directory. If sudo isn't available or the prompt fails, it aborts without touching your working install. Re-run the install script to recover:
curl -fsSL https://raw.githubusercontent.com/HorizonUnix/ZenTune/main/install.sh | bashConfig and presets are backed up to /opt/zentune/config.ini.bak and custom.json.bak (the updater restores them on success). If the new version is broken, re-run the installer:
curl -fsSL https://raw.githubusercontent.com/HorizonUnix/ZenTune/main/install.sh | bashIf an update died halfway, the old app dir may be at /opt/zentune/src.bak:
sudo rm -rf /opt/zentune/src
sudo mv /opt/zentune/src.bak /opt/zentune/src
sudo launchctl kickstart -k system/com.horizonunix.zentuneCollect this before opening an issue:
# OS version
sw_vers
# Python version
python3 --version
# CPU info
sysctl machdep.cpu.family machdep.cpu.model machdep.cpu.brand_string
# Backend state
kextstat | grep DirectHW
sysctl kern.bootargs
# Daemon logs
tail -100 /var/log/zentune.log
# App config
cat /opt/zentune/src/Assets/config.iniOpen an issue on GitHub with this output and a description of what you were doing.
Getting started
Using the app
Internals