openclaw - ✅(Solved) Fix openclaw gateway restart + systemd Restart=always = EADDRINUSE spawn loop [1 pull requests, 2 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#75115Fetched 2026-05-01 05:38:01
View on GitHub
Comments
2
Participants
3
Timeline
4
Reactions
2
Author
Timeline (top)
commented ×2closed ×1cross-referenced ×1

Error Message

Gateway failed to start: another gateway instance is already listening on ws://127.0.0.1:18789 | listen EADDRINUSE: address already in use 127.0.0.1:18789

This repeats every ~45 seconds for 15+ minutes.

Fix Action

Workaround

Use systemctl --user restart openclaw-gateway instead of openclaw gateway restart when running under systemd.

PR fix notes

PR #75144: fix(cli): exit with code 78 on EADDRINUSE to prevent systemd restart loop (#75115)

Description (problem / solution / changelog)

Summary

When openclaw gateway fails to bind due to EADDRINUSE (another instance already listening), it now exits with code 78 (EX_CONFIG) instead of 0.

Closes #75115

Problem

When openclaw gateway restart is used with a systemd service configured with Restart=always:

  1. openclaw gateway restart sends SIGTERM to the running gateway
  2. systemd TimeoutStopSec fires → SIGKILL
  3. systemd immediately spawns a new gateway (Restart=always)
  4. openclaw gateway restart also spawns its own child process
  5. Two processes race for port 18789
  6. The loser gets EADDRINUSE, exits with code 0 (isHealthyGatewayLockError)
  7. systemd sees exit 0 and restarts again (Restart=always restarts on ANY exit)
  8. Loop continues with 19+ retry attempts, each burning CPU

Fix

Change the exit code for healthy lock errors (EADDRINUSE / gateway already running) from 0 to 78 (EXIT_CONFIG_ERROR). This matches the existing RestartPreventExitStatus=78 configuration in the systemd service file, which tells systemd to stop restarting.

Exit code 78 (EX_CONFIG from sysexits.h) is already used elsewhere in the codebase for configuration-related failures (lines 565, 706, 767, 797 of run.ts). The constant EXIT_CONFIG_ERROR = 78 is defined at line 101.

Testing

All related tests pass:

  • gateway-cli.coverage.test.ts — 13 tests pass (updated expected exit code from 0 to 78)
  • run.supervised-lock.test.ts — 4 tests pass
  • http-listen.test.ts — 3 tests pass

Risk Assessment

Low risk. The only behavior change is the exit code for a specific error path:

  • Previously: exit 0 (success) — confused systemd into restarting
  • Now: exit 78 (config error) — systemd respects RestartPreventExitStatus=78
  • Non-systemd users: exit 78 instead of 0 on port conflict; no other behavioral impact
  • The isHealthyGatewayLockError guard is unchanged — only the exit code differs

Context vs. related PR

This change intentionally exits with 78 (EX_CONFIG) instead of 0, which is a narrower and more systemd-safe fix than the existing #44476 approach.

  • Restart=always + RestartPreventExitStatus=78 stops the restart storm on port conflict.
  • Restart=on-failure also stops the restart storm, because RestartPreventExitStatus takes precedence even though exit 78 is non-zero.
  • Exit 0 can silently confuse lifecycle tooling: it looks like a clean successful run, even though startup failed.
  • Exit 78 makes the failure explicit while still preventing restart loops, so it is safer for both systemd and launchd supervisors.

So this is a safer drop-in alternative to the exit-0 behavior described in #44476.

Changed files

  • src/cli/gateway-cli.coverage.test.ts (modified, +1/-1)
  • src/cli/gateway-cli/run.ts (modified, +1/-1)

Code Example

Gateway failed to start: another gateway instance is already listening on ws://127.0.0.1:18789 | listen EADDRINUSE: address already in use 127.0.0.1:18789
RAW_BUFFERClick to expand / collapse

Bug

When openclaw gateway restart is used with a systemd service configured with Restart=always, it causes a spawn loop of zombie gateway processes that burn CPU.

Setup

  • OpenClaw v2026.4.26
  • systemd user service with Restart=always, RestartSec=5, TimeoutStopSec=30

What happens

  1. openclaw gateway restart sends SIGTERM to running gateway
  2. Gateway tries to drain active tasks (up to 30s)
  3. systemd TimeoutStopSec fires → SIGKILL
  4. systemd immediately spawns a new gateway process (Restart=always)
  5. openclaw gateway restart also spawns its own new child process
  6. Two new processes race for port 18789
  7. The loser gets EADDRINUSE, exits with a non-78 code
  8. systemd sees the exit and restarts again (Restart=always, no RestartPreventExitStatus match)
  9. 19+ retry attempts, each loading all plugins, running migrations, failing to bind, exiting
  10. Each zombie burns ~100% CPU for 30-60 seconds while loading

Expected behavior

The gateway should exit with code 78 on EADDRINUSE so that systemd's RestartPreventExitStatus=78 (already configured in the default service file) prevents the restart loop.

Alternatively, when the gateway detects it's running under systemd (OPENCLAW_SYSTEMD_UNIT env var is set), it should delegate restart to systemctl restart instead of spawning its own child.

Workaround

Use systemctl --user restart openclaw-gateway instead of openclaw gateway restart when running under systemd.

Logs

Gateway failed to start: another gateway instance is already listening on ws://127.0.0.1:18789 | listen EADDRINUSE: address already in use 127.0.0.1:18789

This repeats every ~45 seconds for 15+ minutes.

Environment

  • WSL2 (Ubuntu)
  • Node v22.22.0
  • 4 plugins loaded (browser, lossless-claw, memory-core, telegram)
  • Gmail watcher hook active

extent analysis

TL;DR

Use systemctl --user restart openclaw-gateway instead of openclaw gateway restart to avoid the spawn loop of zombie gateway processes.

Guidance

  • When running under systemd, use the systemctl command to restart the service instead of the openclaw gateway restart command to prevent the restart loop.
  • Verify that the RestartPreventExitStatus=78 configuration is set in the systemd service file to prevent restarts when the gateway exits with code 78.
  • Check the gateway logs for the EADDRINUSE error to confirm that the issue is related to the port binding conflict.
  • Consider setting the OPENCLAW_SYSTEMD_UNIT environment variable to enable the gateway to detect when it's running under systemd and delegate restarts to systemctl.

Example

No code snippet is necessary in this case, as the solution involves using a different command to restart the service.

Notes

This workaround assumes that the systemctl command is available and configured correctly on the system. If the issue persists, further investigation into the systemd configuration and the gateway's restart behavior may be necessary.

Recommendation

Apply the workaround by using systemctl --user restart openclaw-gateway instead of openclaw gateway restart, as it is a safer and more reliable way to restart the service under systemd.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

The gateway should exit with code 78 on EADDRINUSE so that systemd's RestartPreventExitStatus=78 (already configured in the default service file) prevents the restart loop.

Alternatively, when the gateway detects it's running under systemd (OPENCLAW_SYSTEMD_UNIT env var is set), it should delegate restart to systemctl restart instead of spawning its own child.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix openclaw gateway restart + systemd Restart=always = EADDRINUSE spawn loop [1 pull requests, 2 comments, 3 participants]