Skip to content

fix(trayicon): skip tray init on headless Linux/BSD instead of crashing#38

Merged
MudDev merged 1 commit into
mainfrom
fix/trayicon-headless
May 18, 2026
Merged

fix(trayicon): skip tray init on headless Linux/BSD instead of crashing#38
MudDev merged 1 commit into
mainfrom
fix/trayicon-headless

Conversation

@MudDev
Copy link
Copy Markdown

@MudDev MudDev commented May 18, 2026

Summary

Fixes #34. On a headless Linux box (server, SSH without X forwarding, container, CI), startup crashes with Xlib.error.DisplayNameError: Bad display name "" and EpixNet refuses to run.

Root cause

plugins/Trayicon/TrayiconPlugin.py:66 imports pystray inside a try/except ImportError. On Linux, pystray's __init__.py selects the _xorg backend at import time, which calls Xlib.display.Display(). With no $DISPLAY set, that raises Xlib.error.DisplayNameError — not an ImportError — so the guard misses it and the unhandled exception aborts actions.main().

The Trayicon plugin is "default": "enabled" (plugin_info.json), so every headless Linux user hits this on first run.

Fix

Two layers of defense in TrayiconPlugin.py:

  1. Pre-check on Linux/BSD: if neither DISPLAY nor WAYLAND_DISPLAY is set, log "no display detected" and continue startup without the tray icon. Avoids even attempting the import, so the user sees a clean message instead of a traceback.
  2. Broaden the import guard: catch Exception (in addition to ImportError) so backend-init failures from any platform (X11 connection refused, future Wayland backends, broken macOS AppKit) degrade gracefully to "tray unavailable" instead of crashing.

super().main() is called in both branches, so the rest of EpixNet boots normally.

Test plan

  • python3 -c "import ast; ast.parse(open('plugins/Trayicon/TrayiconPlugin.py').read())" — syntax OK
  • Reproduce: on a headless Linux box, unset DISPLAY && python3 epixnet.py — verify clean "no display detected" log and successful boot
  • On a normal Linux desktop with $DISPLAY set, verify tray icon still appears
  • On Windows / macOS, verify behavior unchanged (pre-check is gated by sys.platform)

Workaround for affected users until merged

Rename plugins/Trayiconplugins/disabled-Trayicon to disable the plugin.

pystray's _xorg backend opens an X11 connection at import time. On a
headless Linux box (server, SSH session without forwarding, container,
CI) this raises Xlib.error.DisplayNameError("") — not an ImportError —
so the existing except ImportError guard misses it and the daemon
fails to start.

- Short-circuit on Linux/BSD when neither DISPLAY nor WAYLAND_DISPLAY
  is set: log "no display detected" and continue startup without the
  tray icon.
- Broaden the import guard to Exception so any backend-init failure
  (X11 connection refused, AppKit weirdness on macOS, future Wayland
  backends) degrades to "tray unavailable" rather than crashing.

Fixes #34
@MudDev MudDev mentioned this pull request May 18, 2026
@MudDev MudDev merged commit 61302be into main May 18, 2026
3 checks passed
@MudDev MudDev deleted the fix/trayicon-headless branch May 18, 2026 23:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bad display name ""

1 participant