HydraIssues

hydrarelease updater: hardcoded systemd service name guess misses real units
done bug Project: Reporter: 11 May 2026 16:48

Description

Symptom

During manual hydraguard update on the hub today (binary v1.10.2 → v1.10.8), the updater swapped the disk binary correctly but printed:

Restarting service hydraguard-api...
Warning: failed to restart hydraguard-api: exit status 5
Output: Failed to restart hydraguard-api.service: Unit hydraguard-api.service not found.

The actual systemd unit on the hub is hydraguard.service (per the hydraguard runbook and confirmed via systemctl list-units). The updater guessed hydraguard-api.service, which doesn't exist.

Impact

With the restart step silently failing, the new binary sits on disk but the running daemon is still the OLD version in memory. Operators get a green 'Update completed successfully!' message and assume the upgrade is live — but until someone notices and runs systemctl restart hydraguard manually, the service keeps serving the old code.

This is the worst kind of half-success: looks done, isn't done, no alerting.

Likely root cause

The updater probably has a hardcoded heuristic like serviceName := binaryName + "-api" or a per-project mapping that got stale. Different projects use different conventions:

  • hydraguard hub: hydraguard.service ← updater guessed hydraguard-api.service, missed
  • hydraneck: hydraneck.service ← updater seems to get this right
  • hydraheadflatscreen: Windows scheduled task ('HydraHeadWindows' for backward compat) / macOS launchd plist — totally different, also hardcoded somewhere

A hardcoded guess can't possibly be right across this matrix.

Suggested fix

Let the per-project config tell the updater what to restart, rather than guessing:

# In each project's release/updater config
restart_after_update:
  systemd: hydraguard.service        # Linux
  launchd: com.experiencenet.hydraheadflatscreen   # macOS
  scheduled_task: HydraHeadWindows   # Windows

Or inspect the running process: read /proc/self/status or check which unit owns the PID via systemctl status --no-pager $(systemd-cat -t self) style discovery. More fragile but works without config.

Minimum-viable fix: stop guessing. If no explicit restart_after_update config is set, just instruct the operator to restart manually and exit non-zero. Better to be loud than silently fail.

Verification

  1. Updater config exposes the unit name per service.
  2. hydraguard update on the hub restarts hydraguard.service and systemctl is-active hydraguard returns active with a new PID.
  3. Cross-check hydraheadflatscreen still works (its mechanism is different — scheduled task on Windows, launchd on macOS).

Related

Discovered alongside the unbounded-.backup-suffix bug (issue #147). Both are in the same hydrarelease/pkg/updater library.

Custom Fields

affected_repo
hydrarelease (pkg/updater)
discovered_via
manual hydraguard update on hub 2026-05-11
related_issue
147 (updater .backup filename chain)

Comments (1)

api 11 May 2026 18:02

Fixed in hydraguard v1.10.9 (commit 9d092e3).

Corrected the service name from "hydraguard-api" to "hydraguard" in both internal/cli/common.go:83 and internal/cli/serve.go:84, and removed the matching stale claim in README.md.

Footnote on the framing: the bug was not actually in the updater itself — it faithfully restarts whatever service name it is told. The wrong name was hardcoded on the hydraguard side and the updater dutifully called systemctl restart hydraguard-api which does not exist on the hub. Fix is therefore a one-line string change in the consumer, not a contract change in the library.

Deployed to Brussels hub: new daemon PID 810808 confirmed running v1.10.9 via journal logs. All peers healthy, transfer counters preserved across restart. Future updates will now actually swing the running process onto the new binary instead of silently leaving it on the old one.