Version: memtrace 1.0.9 (upgraded 2026-08-10 15:34 local; the prior version had been running since at least 08-04)
Platform: Windows 11 Pro 10.0.26200, Node v24.14.0, 16-core
MCP client: Claude Code (300 s tool idle timeout)
Backend: memdb, workspace store at C:\Users\<user>\Code\.memdb, 12 watched repos
Summary
The 1.0.9 upgrade re-registered every watched repository using Win32 extended-length (\\?\) paths without removing the pre-existing plain-path entries. watches.json now holds 24 entries for 12 repositories — each repo registered twice, under two spellings of the same directory.
After this, list_indexed_repositories never returns. The client aborts it at the 300 s idle timeout. Every per-repo scoped call against the same store in the same daemon returns instantly, so the database itself is fine — it is repository enumeration that is broken.
This is a total-outage failure mode, because list_indexed_repositories is documented as the mandatory first call and the scoped tools refuse to proceed without the repo_id it would return.
Evidence: the duplication is exactly 1:1 and timestamped to the upgrade
~/.memtrace/watches.json:
total watch entries : 24
distinct repo_ids : 12
plain-path entries : 12
\\?\-prefixed : 12
Every one of the 12 repos appears exactly twice. Same repo, same branch, two path spellings:
2026-08-10T14:35:59Z is the upgrade, to the second: the 1.0.9 binary has mtime 08-10 15:34:56 local and the daemon started 15:35:36 local (= 14:35:36 UTC). All 12 \\?\ entries were written in a 160 ms burst 23 s after daemon start.
runtime.json corroborates the switch — its workspaceMembers are now exclusively \\?\-prefixed, while the pre-existing watch entries are not.
Symptom 1 — list_indexed_repositories hangs, and never even logs
Task failed: MCP server "memtrace" tool "list_indexed_repositories" sent no response
or progress for 300s; aborting.
Reproduced twice, ~35 min apart, plus once independently by a separate agent process.
memcore-server.log contains no entry for any of these calls. Its last line is 15:19:41; the calls were at ~15:52 and ~16:55. The call does not reach a point where it logs anything — consistent with blocking on lock acquisition before doing any work. If enumeration takes a per-repo lock and the repo list contains the same store twice, a non-reentrant lock self-deadlocks on the second acquisition.
Symptom 2 — same DB, scoped call, instant
Immediately after the aborted call:
get_repository_stats(repo_id="my-repo") → instant
{"_backend":"memdb","repo_id":"my-repo","branch":"master",
"total_nodes":114222,"total_edges":234195,"community_count":415,
"episode_count":655,"symbol_node_count":4039,"indexing_incomplete":false}
mem_diag also returns instantly. So: process-level calls fine, per-repo scoped reads fine, enumeration hangs forever.
Symptom 3 — 12.3 % of a core, sustained, for 25 hours
|
|
| Daemon |
single instance on 127.0.0.1:3030 |
| Uptime |
25.4 h |
| CPU consumed |
11,206 s (~12.3 % of one core, continuously) |
| RSS |
493 MB |
memcore-server.log shows index maintenance: pruned dead/cold rids from prop_index firing every ~5 minutes for 25 hours without pause, dropping up to 32,307 rids in a single pass:
14:39:16 dropped 500 15:14:39 dropped 1027
14:44:18 dropped 173 15:19:41 dropped 23799
13:58:57 dropped 32307 09:57:32 dropped 16263
24 watchers on 12 directories means every file save is ingested twice, which would produce exactly this churn. Note live_records: 2081697 against total_nodes: 114222 — ~18× more live records than nodes.
Possibly contributing — startup served traffic with structural indexes unbuilt
From the 08-10 boot:
WARN structural index fast-path unavailable on large store; deferring full iter_live repair
until after startup
db=memtrace live_records=2081697 wal_high_water_bytes=36637
rid_uuid=false edge_adj=false count_store=true property_idx=false
WARN deferred structural index repair started; UI/API were already ready
WARN deferred primary record-index checkpoint started; UI/API were already ready
WARN deferred HNSW recovery incomplete vs durable VectorBlobs — repairing the missing vectors
node_count=4449 live_vectorblobs=0
Three structural indexes reported unavailable while the API was already accepting requests. If enumeration depends on property_idx or rid_uuid and falls back to a full iter_live scan over 2.08 M records — twice, once per duplicate registration — that is another route to the same unbounded hang.
Impact
list_indexed_repositories is documented as:
ALWAYS call this first to discover available repo_ids — most other tools require a repo_id.
and the scoped tools refuse to infer one:
{"error_code":"repo_scope_required","scope_required":true,"scope_unresolvable":true,
"diagnostic":{"message":"No explicit repo_id/scope was provided, and the current workspace does not identify one safe repository."}}
So an agent following the documented flow is fully blocked: discovery hangs for 300 s, then every downstream tool refuses for want of the repo_id it never got. Observed directly — an agent burned its full 300 s budget here and silently fell back to ripgrep, degrading its results without the user knowing why.
Workaround (confirmed)
Skip discovery; pass repo_id explicitly. It can be read from disk:
All scoped tools then behave normally. Only usable by someone who knows the file exists.
Suggested fixes
- Make watch registration idempotent by canonical path. Normalise
\\?\-prefixed and plain Windows paths to one canonical form before registering, and de-duplicate on upgrade. This is the root cause.
- Ship a one-time migration that collapses existing duplicate entries — users upgrading from pre-1.0.9 are already in this state and have no signal that anything is wrong.
- Bound
list_indexed_repositories. It should fail fast with a diagnostic rather than hang unbounded, given it sits behind an "ALWAYS call this first" instruction.
- Emit progress events during enumeration so MCP idle timeouts do not fire on merely-slow work.
- Let scoped tools fall back to
.memtrace-store-scope.json when enumeration is unavailable. Returning scope_unresolvable while that file names exactly one member turns a recoverable state into a fatal one.
Minor issues noticed while diagnosing
~/.memtrace/last-run-version still reads 0.6.20 — never updated across many upgrades, including this one. If anything gates migrations on it, those migrations are not running.
- Stale
daemon.pid in the per-repo .memdb directory points at a PID from three days earlier that is no longer running, while the workspace-level .memdb/daemon.pid is correct.
- Index 5 days stale.
last_episode_time = 2026-08-06T23:13:40Z and last_indexed = null on 08-11, despite continuous work in a watched repo and 24 active watchers. indexed_node_count is null while total_nodes is populated.
Version: memtrace 1.0.9 (upgraded 2026-08-10 15:34 local; the prior version had been running since at least 08-04)
Platform: Windows 11 Pro 10.0.26200, Node v24.14.0, 16-core
MCP client: Claude Code (300 s tool idle timeout)
Backend:
memdb, workspace store atC:\Users\<user>\Code\.memdb, 12 watched reposSummary
The 1.0.9 upgrade re-registered every watched repository using Win32 extended-length (
\\?\) paths without removing the pre-existing plain-path entries.watches.jsonnow holds 24 entries for 12 repositories — each repo registered twice, under two spellings of the same directory.After this,
list_indexed_repositoriesnever returns. The client aborts it at the 300 s idle timeout. Every per-repo scoped call against the same store in the same daemon returns instantly, so the database itself is fine — it is repository enumeration that is broken.This is a total-outage failure mode, because
list_indexed_repositoriesis documented as the mandatory first call and the scoped tools refuse to proceed without therepo_idit would return.Evidence: the duplication is exactly 1:1 and timestamped to the upgrade
~/.memtrace/watches.json:Every one of the 12 repos appears exactly twice. Same repo, same branch, two path spellings:
{ "path": "C:\\Users\\<user>\\Code\\my-repo", "repo_id": "my-repo", "branch": "master", "registered_at": "2026-08-04T10:20:37.536446200+00:00", "origin": "manual" }, { "path": "\\\\?\\C:\\Users\\<user>\\Code\\my-repo", "repo_id": "my-repo", "branch": "master", "registered_at": "2026-08-10T14:35:59.413590300+00:00", "origin": "manual" }2026-08-10T14:35:59Zis the upgrade, to the second: the 1.0.9 binary has mtime08-10 15:34:56local and the daemon started15:35:36local (= 14:35:36 UTC). All 12\\?\entries were written in a 160 ms burst 23 s after daemon start.runtime.jsoncorroborates the switch — itsworkspaceMembersare now exclusively\\?\-prefixed, while the pre-existing watch entries are not.Symptom 1 —
list_indexed_repositorieshangs, and never even logsReproduced twice, ~35 min apart, plus once independently by a separate agent process.
memcore-server.logcontains no entry for any of these calls. Its last line is15:19:41; the calls were at ~15:52 and ~16:55. The call does not reach a point where it logs anything — consistent with blocking on lock acquisition before doing any work. If enumeration takes a per-repo lock and the repo list contains the same store twice, a non-reentrant lock self-deadlocks on the second acquisition.Symptom 2 — same DB, scoped call, instant
Immediately after the aborted call:
{"_backend":"memdb","repo_id":"my-repo","branch":"master", "total_nodes":114222,"total_edges":234195,"community_count":415, "episode_count":655,"symbol_node_count":4039,"indexing_incomplete":false}mem_diagalso returns instantly. So: process-level calls fine, per-repo scoped reads fine, enumeration hangs forever.Symptom 3 — 12.3 % of a core, sustained, for 25 hours
memcore-server.logshowsindex maintenance: pruned dead/cold rids from prop_indexfiring every ~5 minutes for 25 hours without pause, dropping up to 32,307 rids in a single pass:24 watchers on 12 directories means every file save is ingested twice, which would produce exactly this churn. Note
live_records: 2081697againsttotal_nodes: 114222— ~18× more live records than nodes.Possibly contributing — startup served traffic with structural indexes unbuilt
From the 08-10 boot:
Three structural indexes reported unavailable while the API was already accepting requests. If enumeration depends on
property_idxorrid_uuidand falls back to a fulliter_livescan over 2.08 M records — twice, once per duplicate registration — that is another route to the same unbounded hang.Impact
list_indexed_repositoriesis documented as:and the scoped tools refuse to infer one:
{"error_code":"repo_scope_required","scope_required":true,"scope_unresolvable":true, "diagnostic":{"message":"No explicit repo_id/scope was provided, and the current workspace does not identify one safe repository."}}So an agent following the documented flow is fully blocked: discovery hangs for 300 s, then every downstream tool refuses for want of the
repo_idit never got. Observed directly — an agent burned its full 300 s budget here and silently fell back toripgrep, degrading its results without the user knowing why.Workaround (confirmed)
Skip discovery; pass
repo_idexplicitly. It can be read from disk:All scoped tools then behave normally. Only usable by someone who knows the file exists.
Suggested fixes
\\?\-prefixed and plain Windows paths to one canonical form before registering, and de-duplicate on upgrade. This is the root cause.list_indexed_repositories. It should fail fast with a diagnostic rather than hang unbounded, given it sits behind an "ALWAYS call this first" instruction..memtrace-store-scope.jsonwhen enumeration is unavailable. Returningscope_unresolvablewhile that file names exactly one member turns a recoverable state into a fatal one.Minor issues noticed while diagnosing
~/.memtrace/last-run-versionstill reads0.6.20— never updated across many upgrades, including this one. If anything gates migrations on it, those migrations are not running.daemon.pidin the per-repo.memdbdirectory points at a PID from three days earlier that is no longer running, while the workspace-level.memdb/daemon.pidis correct.last_episode_time=2026-08-06T23:13:40Zandlast_indexed=nullon 08-11, despite continuous work in a watched repo and 24 active watchers.indexed_node_countisnullwhiletotal_nodesis populated.