Summary
openclaw daemon status --json reports runtime.status=stopped even when port 18789 has an active listener owned by a previous gateway instance. The status reporter is reading service-registration state and not cross-checking the actual port owner, so it lies in any split-brain scenario.
Repro
Easiest path is via the companion bug (#979 — gateway install --force not idempotent):
- Have a healthy gateway running and listening on 18789
- Run
openclaw gateway install --force → second instance fails with EADDRINUSE, but the first instance keeps running
- Run
openclaw daemon status --json
Observed
{ \"runtime\": { \"status\": \"stopped\" }, ... }
…while netstat -ano | findstr 18789 shows the original node.exe still listening.
Expected
The status reporter should cross-check:
- Is port 18789 currently bound? (if yes, by which PID?)
- Is the bound PID one of our managed gateway instances?
Possible reported states:
| Port listener |
Service registration |
runtime.status |
| ours (matches registration) |
matches |
running |
| no listener |
absent |
stopped |
| listener exists, registration absent or mismatched |
— |
conflict (new) — include the offending PID |
| no listener but registration present |
— |
stale (new) |
At minimum, conflict is needed so downstream tooling can distinguish "daemon is genuinely down" from "daemon is in split-brain after a botched install".
Impact
Discovered during downstream verification (anro-claw issue #825). Downstream L2 acceptance tests trust daemon status --json as the ground-truth health probe — when it lies, real env state gets mis-framed as a regression. We currently work around it by checking netstat 18789 directly, but that's not portable and shouldn't be necessary.
Environment
- Windows 11, Node 20 (bundled)
- Observed on 5060Ti, 2026-04-26
Summary
openclaw daemon status --jsonreportsruntime.status=stoppedeven when port 18789 has an active listener owned by a previous gateway instance. The status reporter is reading service-registration state and not cross-checking the actual port owner, so it lies in any split-brain scenario.Repro
Easiest path is via the companion bug (#979 —
gateway install --forcenot idempotent):openclaw gateway install --force→ second instance fails withEADDRINUSE, but the first instance keeps runningopenclaw daemon status --jsonObserved
{ \"runtime\": { \"status\": \"stopped\" }, ... }…while
netstat -ano | findstr 18789shows the originalnode.exestill listening.Expected
The status reporter should cross-check:
Possible reported states:
runtime.statusrunningstoppedconflict(new) — include the offending PIDstale(new)At minimum,
conflictis needed so downstream tooling can distinguish "daemon is genuinely down" from "daemon is in split-brain after a botched install".Impact
Discovered during downstream verification (anro-claw issue #825). Downstream L2 acceptance tests trust
daemon status --jsonas the ground-truth health probe — when it lies, real env state gets mis-framed as a regression. We currently work around it by checkingnetstat 18789directly, but that's not portable and shouldn't be necessary.Environment