Skip to content

codedb . status leaks a ~20GB resident process that never exits (warmup -> OOM/freeze) #553

@lekt9

Description

@lekt9

Summary

The SessionStart warmup pattern codedb . status & leaks a ~20 GB resident process that never exits. Each invocation spawns another one, so on a machine where it runs repeatedly (e.g. a Claude Code SessionStart hook) the orphans accumulate until RAM is exhausted and macOS freezes the UI and force-restarts.

Environment

  • codedb 0.2.5824
  • macOS 26.0.1, Apple Silicon, 64 GB unified memory
  • Invoked from a Claude Code hook: codedb . status >/dev/null 2>&1 & on SessionStart

What happens

  • codedb . status appears to load the full index into memory (~20 GB RSS; ~2.8 GB private/dirty + ~18 GB mmap'd index) and then does not exit — the process stays resident for hours.
  • When backgrounded (&) from a short-lived parent, it is reparented to launchd (ppid=1) and lives forever.
  • Repeated invocations stack: I observed 3 simultaneous orphaned codedb . status processes at ~20 GB RSS each, all ppid=1, plus the live codedb mcp.

Observed via ps:

pid=7591 ppid=1 up=07:04 rss=20.2GB  codedb . status
pid=9377 ppid=1 up=03:50 rss=20.7GB  codedb . status
pid=7585 ppid=7574       rss=20.1GB  codedb mcp     (live, expected)

Impact

On a 64 GB machine this exhausts RAM. With swap effectively at 0, macOS responds with jetsam kills and WindowServer userspace_watchdog_timeout hangs — i.e. the screen freezes and the only recovery is a hard restart. Confirmed from /Library/Logs/DiagnosticReports/:

JetsamEvent-2026-06-07-170555.ips   (largestProcess = python3.12)
WindowServer_..._userspace_watchdog_timeout.spin   (x2)

Reproduce

for i in 1 2 3; do codedb . status >/dev/null 2>&1 & done
sleep 5
ps -axo pid,ppid,rss,command | grep 'codedb . status'   # 3 procs, ~20 GB RSS each, none exit

Expected

  • codedb . status should be a cheap, fast-exiting status query — it should not need to load and hold the entire ~20 GB index resident, and it should return promptly and exit.
  • If warming the index is the intent, that should be an explicit subcommand (e.g. codedb warm) that either (a) hands off to / reuses the already-running daemon rather than spawning a second full copy, or (b) is bounded and reaps itself.

Likely root cause

status seems to mmap/load the whole index (like a query path) and then block instead of exiting — so any &-detached call becomes a permanent ~20 GB orphan, and nothing dedupes against an already-running instance.

Suggested fixes

  1. status should not load the full index — report state from metadata and exit immediately.
  2. If a warm/daemon is desired, make warmup idempotent (no-op when an instance is already running) and self-terminating.
  3. Document that codedb . status must not be backgrounded as a warmup, since it currently never exits.

Workaround (for anyone hitting freezes)

Harden the Claude SessionStart hook so it can't pile up or linger:

command -v codedb >/dev/null 2>&1 || exit 0
pgrep -f 'codedb . status' >/dev/null 2>&1 && exit 0      # no pile-up
{ codedb . status >/dev/null 2>&1 & cp=$!
  ( sleep 30; kill -9 "$cp" 2>/dev/null ) & wp=$!
  wait "$cp" 2>/dev/null; kill "$wp" 2>/dev/null; } >/dev/null 2>&1 &

And reap existing orphans:

ps -axo pid,ppid,command | awk '$2==1 && /codedb . status/{print $1}' | xargs kill -9

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions