OpenClaw Zombie Sessions in sessions.json After Subagent Crash
You spawn a subagent. It crashes — maybe the host rebooted, maybe you sent a SIGKILL, maybe it just died. You restart your gateway and everything looks fine. But quietly, sessions.json has grown another stale ghost entry with status: "running" that will never go away on its own.
Over time, this file accumulates hundreds of zombie entries. External monitoring scripts that read it directly see agents that haven't existed for weeks. And the file keeps growing.
What's Happening
OpenClaw tracks active subagent sessions in two places:
- An in-memory registry — used by the
subagentstool API ~/.openclaw/agents/main/sessions/sessions.json— the persistent file on disk
When a subagent exits cleanly, both get updated. When a subagent crashes (SIGKILL, host reboot, OOM kill), only the in-memory registry gets cleaned up on the next gateway start. The sessions.json entry is never touched — it stays status: "running" with the original startedAt timestamp, forever.
This creates a split-brain state: the subagents API shows nothing, but sessions.json shows it as actively running.
How to Tell If You Have Zombies
# Check for entries with status "running" that are old
cat ~/.openclaw/agents/main/sessions/sessions.json | \
python3 -c "
import json, sys, datetime
data = json.load(sys.stdin)
now = datetime.datetime.utcnow()
for s in data.get('sessions', []):
if s.get('status') == 'running':
started = s.get('startedAt', '')
print(f\"RUNNING: {s.get('id','?')} started={started}\")
"
If you see sessions marked running with timestamps from hours or days ago — those are zombies.
Manual Cleanup (The Current Workaround)
Until OpenClaw adds automatic TTL-based cleanup, you'll need to edit the file manually or use a script.
Option 1: Quick Manual Edit
# Back it up first
cp ~/.openclaw/agents/main/sessions/sessions.json \
~/.openclaw/agents/main/sessions/sessions.json.bak
# Open and remove stale "running" entries
nano ~/.openclaw/agents/main/sessions/sessions.json
Remove any entries where status is "running" and the startedAt timestamp is more than 30 minutes ago (and you know no subagent is actually running).
Option 2: Cleanup Script
Save this as cleanup-sessions.py and run it when needed (with the gateway stopped):
import json, os, datetime
path = os.path.expanduser(
"~/.openclaw/agents/main/sessions/sessions.json"
)
with open(path) as f:
data = json.load(f)
now = datetime.datetime.utcnow()
cutoff = 30 * 60 # 30 minutes in seconds
cleaned = []
removed = 0
for s in data.get("sessions", []):
if s.get("status") == "running":
started_str = s.get("startedAt", "")
try:
started = datetime.datetime.fromisoformat(
started_str.replace("Z", "+00:00")
).replace(tzinfo=None)
age = (now - started).total_seconds()
if age > cutoff:
print(f"Removing zombie: {s.get('id')} (age {age/60:.0f}m)")
removed += 1
continue
except Exception:
pass
cleaned.append(s)
data["sessions"] = cleaned
with open(path, "w") as f:
json.dump(data, f, indent=2)
print(f"Done. Removed {removed} zombie session(s).")
openclaw gateway stop
python3 cleanup-sessions.py
openclaw gateway start
Option 3: Cron-Based Maintenance
If you run long-lived gateways with lots of subagent activity, schedule the cleanup script daily:
# Add to crontab (runs at 3 AM daily)
0 3 * * * openclaw gateway stop && python3 ~/cleanup-sessions.py && openclaw gateway start
Impact on Your Setup
For most users with occasional subagent use, this is a minor annoyance. For power users running automated pipelines with dozens of subagents per day, sessions.json can grow to thousands of stale entries within weeks, and any external tooling that reads it directly will give garbage data.
When Will It Be Fixed?
The fix involves one of two approaches: process-exit hooks that update sessions.json on abnormal termination, or a startup reconciliation pass that marks stale running entries as crashed. Track progress at issue #67902.
Need Help?
If your OpenClaw setup is accumulating session cruft or you want a properly maintained multi-agent configuration, ClawReady can help you get it clean and keep it that way.