Skip to content

openclaw doctor --fix regenerates user-systemd unit even when system unit owns the gateway, causing dual-instance deadlock #62764

Description

@tmote

Bug: openclaw doctor --fix regenerates a user-systemd unit even when a system-systemd unit owns the gateway, causing dual-instance deadlock

Environment

  • OpenClaw 2026.4.5 (3e72c03)
  • Ubuntu 24.04.4 LTS, systemd 255
  • Node v24.14.1 via nvm
  • openclaw-gateway running as a system-systemd unit at /etc/systemd/system/openclaw-gateway.service (User=pleresadmin), so the gateway can use LoadCredentialEncrypted= to inject Microsoft Teams client secrets from /etc/credstore.encrypted/

Background — why a system unit instead of user-systemd

The default OpenClaw onboarding installs a user-systemd unit at ~/.config/systemd/user/openclaw-gateway.service. We migrated to a system-systemd unit (still running as User=pleresadmin) because user-systemd cannot consume LoadCredentialEncrypted= paths in /etc/credstore.encrypted/ — only system-systemd can decrypt host-key-sealed credentials. Both LiteLLM and openclaw-gateway use this pattern in our deployment for secret injection.

After migration:

  • ~/.config/systemd/user/openclaw-gateway.service was disabled and removed
  • /etc/systemd/system/openclaw-gateway.service was installed, enabled, and started
  • The gateway came up cleanly, both signal-cli daemons + msteams sidecar live

Steps to reproduce

  1. Have the gateway running successfully under a system-systemd unit. Confirm:
    systemctl --user is-enabled openclaw-gateway   # → not-found
    sudo systemctl is-active openclaw-gateway       # → active
    
  2. Run openclaw doctor --fix (for any reason — we ran it during a security-audit pass).
  3. Doctor silently writes back both unit files:
    • ~/.config/systemd/user/openclaw-gateway.service (regenerated even though it had been deleted)
    • And enables it via systemctl --user enable
  4. Now both systemd unit files exist with the same name. Doctor doesn't mention this anywhere in its output.

Expected behavior

Doctor should:

  • Detect existing system-systemd installation at /etc/systemd/system/openclaw-gateway.service
  • Skip user-systemd unit regeneration when the system unit owns the gateway
  • OR at minimum, warn loudly that it's about to install a second unit with the same name

Actual behavior

Both units come up. Both bind port 18789. They detect each other as "stale gateway" via OpenClaw's internal service-mode cleanup subsystem (which kills processes that hold port 18789 when a new instance starts). Each new instance of one unit kills the running instance of the other. Result:

  • 17-second crash loop, perfectly deterministic
  • systemd journal shows Main process exited, code=killed, status=9/KILL every 17 seconds
  • restart counter climbs (Restart=always is set)
  • All four service ports (gateway WS 18789, msteams 3978, signal-cli 8080/8081) come up briefly during each instance's brief life, then disappear when the killer fires

Diagnostic difficulty

The 17-second SIGKILL pattern looks like:

  • OOM killer (no — system has 12 GB free)
  • systemd timeout (no — TimeoutStartSec=120)
  • Channel sidecar hang (no — happens with both signal AND msteams disabled)
  • Namespace setup failure (no — minimal hardening, no ProtectSystem=strict)

It took several hours of debugging to find the dual-unit cause. The actual smoking gun was:

$ systemctl --user is-enabled openclaw-gateway
enabled
$ systemctl --user is-active openclaw-gateway
active

For a unit file I had explicitly deleted earlier in the session.

Workaround

After running openclaw doctor --fix on a system-systemd installation:

systemctl --user stop openclaw-gateway
systemctl --user disable openclaw-gateway
rm -f ~/.config/systemd/user/openclaw-gateway.service ~/.config/systemd/user/openclaw-gateway.service.bak
systemctl --user daemon-reload
sudo systemctl stop openclaw-gateway
sudo pkill -9 -f openclaw-gateway
sudo pkill -9 -f signal-cli
sudo systemctl reset-failed openclaw-gateway
sudo systemctl start openclaw-gateway

Severity

High, especially in combination with bug #22 (signal multi-account corruption) — both fire on the same --fix invocation. A user running openclaw doctor --fix once for a routine cleanup pass can take their entire deployment down with no obvious cause.

Suggested fix paths

  1. Doctor's daemon-install pathway should check for an existing /etc/systemd/system/openclaw-gateway.service BEFORE writing the user-systemd version. If present, skip user-unit installation entirely.
  2. Optionally, surface a warning if the user has both unit files: "Multiple unit files detected — pick one and remove the other."
  3. Document the system-systemd installation path as a first-class option for users who need LoadCredentialEncrypted= (currently it's a manual migration with no doctor support).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions