Skip to content

Stale rendezvous directory (/tmp/cbm-daemon-<uid>) permanently blocks install/update with "active CBM sessions ... could not be stopped safely" after hard-killed CBM processes #1760

Closed

Description

@hansinator85

Version

codebase-memory-mcp 0.10.8

Platform

macOS (Apple Silicon)

Install channel

GitHub release archive / install.sh / install.ps1

Binary variant

standard

What happened, and what did you expect?

Title

Stale rendezvous directory (/tmp/cbm-daemon-<uid>) permanently blocks install/update with "active CBM sessions ... could not be stopped safely" after hard-killed CBM processes

Summary

After several long-lived codebase-memory-mcp MCP server processes were terminated non-gracefully (pkill, no clean shutdown), every subsequent codebase-memory-mcp install and codebase-memory-mcp update call failed permanently with:

Stopping active CBM sessions and operations for install...
error: active CBM sessions and operations could not be stopped safely; no activation was committed.
error: something is still using CBM. If an editor or agent is running an MCP server, close it and retry; 'codebase-memory-mcp daemon status' lists the holders when a cbm binary is still installed.

This happened even though every process-level and file-lock check came back completely clean:

  • ps aux | grep codebase-memory-mcp → no matches
  • codebase-memory-mcp daemon status → daemon: not running
  • lsof +D ~/.cache/codebase-memory-mcp → no open handles
  • No *.lock, *.pid, or *.sock files under ~/.cache/codebase-memory-mcp
  • No matching launchctl list entries / no LaunchAgent plist
  • No stray files under $TMPDIR (the per-user /var/folders/.../T/ directory)

The installer's own diagnostics (daemon status, the error message itself) only ever point at "an editor or agent running an MCP server" — i.e. a process-level explanation — which sent us down the wrong debugging path for a long time. The actual blocker is stale on-disk coordination state, not a live process.

Environment

  • OS: macOS (Apple Silicon / arm64)
  • Shell: zsh
  • Install method: official install.sh (curl -fsSL https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.sh | bash), binary at ~/.local/bin/codebase-memory-mcp
  • Affected versions: reproduced going from 0.10.1 → 0.10.8, and again fresh on 0.10.8 → 0.10.8 (re-running install to repair a corrupted agent config, see "related issue" below)
  • ~25 indexed repositories, several coding-agent integrations detected (Claude Code, Codex CLI, VS Code, Junie, OpenHands, GitLab Duo CLI)

Suggested fixes

  1. Self-heal stale/unverified version-cohort claims. If a claim in cbm-version-cohort-*-v1.lock has no live process associated with it (e.g. via flock/holder-PID liveness check), it should be treated as abandoned and cleared automatically, rather than blocking indefinitely.
  2. Improve the error message to name the actual rendezvous directory and file(s) it's stuck on (similar to what v0.10.5's release notes describe doing for the Windows "directory that actually refused" case), instead of only suggesting "an editor or agent is running an MCP server."
  3. Document the rendezvous directory and CBM_RUNTIME_DIR in docs/CONFIGURATION.md — currently CBM_RUNTIME_DIR is only mentioned in one release's changelog.
  4. Provide a supported reset command, e.g. codebase-memory-mcp daemon reset-coordination or similar, instead of requiring users to manually locate and rm -rf an undocumented /tmp directory.
  5. Consider whether daemon status (which correctly reported "not running") should also inspect this rendezvous directory and warn about orphaned/unverified cohort claims even when no daemon process exists.

Workaround (for anyone hitting this)

# 1. Make sure nothing is actually running:
ps aux | grep -i codebase-memory-mcp
codebase-memory-mcp daemon status

# 2. If truly nothing is running but install/update still fails with
#    "active CBM sessions and operations could not be stopped safely":
rm -rf /tmp/cbm-daemon-$(id -u)

# 3. Retry:
codebase-memory-mcp install

Related

Reproduction

Steps to reproduce

  1. Have several coding-agent sessions running that each spawn their own codebase-memory-mcp MCP server subprocess over stdio (no shared daemon — daemon status reports "not running" the whole time).
  2. Let those parent editor/agent windows terminate abnormally (in our case, likely closed without the MCP child process being reaped — we found 15 orphaned codebase-memory-mcp processes, several days old, each with hundreds of CPU-minutes accumulated).
  3. Terminate them non-gracefully:
    pkill -f "/Users/<user>/.local/bin/codebase-memory-mcp"
    
  4. Run codebase-memory-mcp install (or update). It fails with the error above.
  5. Confirm there is genuinely nothing left holding CBM open (steps listed in the Summary). The error persists indefinitely regardless.

Root cause (found via fs_usage)

Since neither the CLI's own diagnostics nor CBM_DIAGNOSTICS=true / CBM_LOG_LEVEL=debug surfaced the actual path being checked (the process exits before the periodic diagnostics writer ever runs), we traced the failing install invocation with:

sudo fs_usage -w -f filesys codebase-memory-mcp

This revealed a per-UID rendezvous/coordination directory that is not documented anywhere in docs/CONFIGURATION.md and is separate from ~/.cache/codebase-memory-mcp:

/private/tmp/cbm-daemon-<uid>/

containing (anonymized, real trace excerpt, timestamps/PID trimmed):

srw-------  cbm-<hash>.anc
-rw-------  cbm-<hash>.lifetime.lock
-rw-------  cbm-<hash>.lock
srw-------  cbm-<hash>.sock
-rw-------  cbm-<hash>.startup-v2.lock
-rw-------  cbm-version-cohort-admission-v1.lock
-rw-------  cbm-version-cohort-daemon-v1.lock
-rw-------  cbm-version-cohort-lifetime-v1.lock   (214 bytes — the only non-empty file)
-rw-------  cbm-version-cohort-maintenance-v1.lock

and, matching this, CBM_LOG_LEVEL=debug on a plain codebase-memory-mcp cli ... invocation (no install) printed:

level=info msg=version_cohort.claimed_unheld build=<sha>
codebase-memory-mcp: CBM CLI could not start because a pre-coordination or unverified CBM generation is active; close all CBM sessions and commands, then retry

Our reading: each CBM process "claims" a version-cohort slot in this directory for its generation/build, and expects a follow-up step to mark that claim as "held"/verified. When a process is killed abruptly (SIGKILL/hard pkill, or a crash — we also found a stale ~/Library/Application Support/CrashReporter/codebase-memory-mcp_*.plist), that follow-up never runs, and the claim is left dangling in cbm-version-cohort-lifetime-v1.lock / cbm-version-cohort-admission-v1.lock forever. Every later install/update/cli invocation sees an "unheld"/unverified claim and refuses to proceed, because from its perspective it cannot prove no other generation is mid-transition — even though, in reality, nothing is running anymore and the claim is simply orphaned.

Confirmed as the actual cause: removing the directory entirely resolved the issue immediately and permanently.

rm -rf /tmp/cbm-daemon-<uid>
codebase-memory-mcp install   # now succeeds

We also found that CBM_RUNTIME_DIR (mentioned only in the v0.10.5 release notes, not in docs/CONFIGURATION.md) can point this coordination logic at a fresh directory as a workaround without touching the default one — useful for anyone who wants to unblock install without deleting the existing rendezvous directory outright:

CBM_RUNTIME_DIR=/tmp/cbm-runtime-clean codebase-memory-mcp install

Note, though, that this creates a split-brain: install then commits its "verified generation" state under the custom CBM_RUNTIME_DIR, while any later plain invocation (cli, an editor's MCP server launch, etc.) that does not set CBM_RUNTIME_DIR falls back to the still-broken default directory and immediately hits the same version_cohort.claimed_unheld / "pre-coordination or unverified CBM generation is active" error. CBM_RUNTIME_DIR is only a safe workaround if set consistently everywhere, or as a stepping stone before clearing and returning to the default directory (which is what ultimately fixed it for us).

Why this was hard to diagnose

The error message and daemon status hint entirely at live processes ("something is still using CBM... an editor or agent is running an MCP server... daemon status lists the holders"). There is no mention that:

  • a per-UID directory under /tmp holds durable cross-run coordination state independent of any running process,
  • that state can be inspected or reset via any documented command,
  • CBM_RUNTIME_DIR exists and affects this exact code path.

This sent us through a long, unproductive diagnostic chain (checking ps, lsof, launchctl, SQLite WAL files, license/session theories, etc.) before fs_usage tracing revealed the real location.

Logs


Diagnostics trajectory (memory / performance / leak issues)


Project scale (if relevant)

No response

Confirmations

  • I searched existing issues and this is not a duplicate.
  • My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code.

Activity

  1. LinRds commented on Aug 27, 2026

    @LinRds

    Hit this on 0.10.8, macOS 15 (Apple Silicon) running install.sh from ~/.local/bin. Same failure text, and the event log shows the refusal happens with zero active clients, which may be the useful part.

    What the installer printed

    Download and checksum both succeeded; the candidate verified as the same version already installed. Then:

    Stopping active CBM sessions and operations for install...
    error: active CBM sessions and operations could not be stopped safely; no activation was committed.
    error: something is still using CBM. If an editor or agent is running an MCP server, close it and retry;
           'codebase-memory-mcp daemon status' lists the holders when a cbm binary is still installed.
    

    Exit code was 0 despite no activation was committed, so a scripted/CI update would record this as success while silently keeping the old binary.

    activation-events.ndjson

    Today's failed run (fields trimmed):

    {"phase":"requested","action":"install","daemon_active_clients":0,"daemon_active_connections":0,...}
    {"phase":"failed","action":"install","daemon_active_clients":0,"daemon_active_connections":0,
     "detail":"cohort drain or coordination failed"}

    For contrast, the successful install of the same version on this machine 8 days earlier:

    {"phase":"daemon_stopped","action":"install","detail":"no active cohort"}
    {"phase":"completed","action":"install","detail":"activation mutation completed; ..."}

    So the drain fails while the installer itself observes daemon_active_clients: 0 and daemon_active_connections: 0.

    Contradictory user-facing signals

    The error message points at daemon status to list the holders, but at that moment:

    $ codebase-memory-mcp daemon status
    daemon: not running
    hint: `codebase-memory-mcp daemon start` keeps a daemon warm so CLI commands and hooks skip the per-command startup cost.
    

    No processes existed either (ps showed zero codebase-memory-mcp). Following the error's own advice therefore dead-ends — there is no way to discover that /tmp/cbm-daemon-<uid> is the blocker.

    Same root cause as the daemon-side failure

    On this machine the stale rendezvous directory was simultaneously blocking daemon start with CBM daemon could not start within 30000 ms (details in #1757 — markerless hard-linked .sock/.anc pair, no .identity/.pending). One rm -rf /tmp/cbm-daemon-501 cleared both failures at once: the daemon started on the next attempt, and install/update work again.

    Suggestions, in rough order of usefulness:

    1. Name the blocking path in the error text — /tmp/cbm-daemon-<uid> — rather than pointing at daemon status, which reports not running in exactly this state.
    2. Return non-zero when no activation was committed.
    3. Recover the rendezvous directory automatically when no process holds the socket and connect returns ECONNREFUSED (this is what PR fix(cli): recover stale rendezvous publication before declaring BUSY (#1760) #1790 appears to be reaching for).
  2. added a commit that references this issue on Aug 31, 2026
    8e70590
  3. gitokato commented on Aug 31, 2026

    @gitokato

    Environment: codebase-memory-mcp 0.10.8 (build 2412e017…), macOS (Apple Silicon), install.sh,
    binary at ~/.local/bin, ui variant. Daemon was watching 4 projects with auto-index/watch on.

    Different symptom: the runtime guard was completely blocked, not just install/update.

    The same stale rendezvous state made every runtime entry point fail with the message:

    codebase-memory-mcp: CBM CLI could not start because a pre-coordination or unverified CBM generation is active; close all CBM sessions and commands, then retry
    

    This blocked all of: the MCP server connection (editor saw CONNECTION_CLOSED),
    codebase-memory-mcp cli <tool>, plain codebase-memory-mcp config list, and the daemon's own
    background index workers
    . Same as here, every process/lock check was clean (pgrep = 0 CBM
    processes; a fresh single-shot config list with no daemon alive still failed).

    The stuck artifacts were the cbm-version-cohort-*-v1.lock family in /tmp/cbm-daemon-<uid>/
    (…lifetime-v1.lock held 214 bytes of state), consistent with a stuck pre-coordination /
    unverified generation
    claim — which may be a different artifact than the .sock/.anc pair that
    PR #1894 targets. Worth checking whether #1894's activation-path recovery also clears a stuck
    version-cohort / unverified-generation claim that blocks the runtime guard, or only the install/update
    path.

    Concrete trigger (captured in cbm-daemon.log)

    The daemon log shows the exact pivot into the wedged state. Workers reap cleanly until one is
    killed mid-generation, and it never recovers after that:

    level=info  msg=index.supervisor.reap outcome=clean exit_code=0 signal=0        # healthy
    ...
    level=warn  msg=index.supervisor.worker_cancelled outcome=killed  log=.../.worker-log-XXXXXX   # <-- PIVOT (worker log 0 bytes)
    ...
    level=info  msg=index.supervisor.reap outcome=exit_nonzero exit_code=1 signal=0
    level=warn  msg=index.supervisor.worker_failed outcome=exit_nonzero exit_code=1  log=.../.worker-log-XXXXXX
    level=warn  msg=watcher.index.err project=<PROJECT-A>
    

    So: a worker killed mid-index left the generation reservation unreleased, and the pre-coordination
    guard then refused every subsequent start. Each failing worker log is identical:

    {"level":"control","event":"index.worker.start","version":"0.10.8","build":"<hash>","pid":"<PID>","repo_path":"<PROJECT-A>","args":"..."}
    level=info msg=version_cohort.claimed_unheld build=<hash>
    CBM index worker could not start: a pre-coordination or unverified CBM generation is active
    

    Amplification: infinite auto-index retry loop

    With auto-index/watch enabled, the file watcher re-fired the index on every watcher.changed for
    a dirty git tree, so the failing worker spawned continuously — ~230 identical failing worker logs
    accumulated and one process sat pinned in R state at high CPU for days. A stuck reservation plus
    auto-index turns a one-time crash into a hot loop.

    Happy to grab a CBM_DIAGNOSTICS=1 trajectory or the activation-events.ndjson if useful — this was
    on a live wedge that's since been cleared, but it's reproducible by killing a worker mid-generation.

  4. added
    priority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.
    on Sep 5, 2026
  5. Tomauskasz commented on Sep 7, 2026

    @Tomauskasz

    Hit this independently today (2026-09-07) on 0.10.8, same symptoms and same root cause.

    One more data point: with the rendezvous dir in this stuck state, codebase-memory-mcp daemon start also fails outright — it times out with CBM daemon could not start within 30000 ms after only printing version_cohort.claimed_unheld to stderr. It never got far enough to write anything to ~/.cache/codebase-memory-mcp/logs/cbm-daemon.log, even with zero live clients and zero daemon processes running. So this isn't limited to install/update/cli — it blocks daemon startup entirely too.

    Confirmed the same fix: rm -rf /tmp/cbm-daemon-$(id -u) resolved it immediately — daemon start and config get/set all worked right after, no reinstall needed.

  6. DeusData commented on Sep 7, 2026

    @DeusData
    Owner

    Fixed on main by 760c08f (PR #1894, thank you @mvanhorn, and thanks to everyone who confirmed the shape here): a hard-killed daemon or worker no longer leaves a markerless .sock/.anc pair plus an unheld cohort lock that wedges install, update and every CLI or MCP entry point behind the 30 s "active or starting" timeout; activation now runs the serialized stale-generation cleanup before classifying. Ships in v0.10.9. If you still hit it on that release, please say so here with daemon status and the contents of /tmp/cbm-daemon-.

  7. added a commit that references this issue on Sep 29, 2026
    35913fb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingeditor/integrationEditor compatibility and CLI integrationpriority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.stability/performanceServer crashes, OOM, hangs, high CPU/memorywindowsWindows-specific issues

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions