Skip to content

query_graph / search_graph return "project not found" inconsistently; DBs valid on disk but CLI looks up wrong inode #704

Closed

Description

@MatiasNAmendola

query_graph / search_graph return "project not found or not indexed" even with a registered, indexed project

Environment

  • Tool: codebase-memory-mcp v0.8.1 (binary download from release, macOS aarch64)
  • OS: macOS 15 (Darwin), APFS filesystem (default case-insensitive, case-preserving)
  • Storage dir: ~/.cache/codebase-memory-mcp/
  • Project indexed: MSBA-MSBA (3034 .cs files, 82,303 nodes / 269,108 edges per list_projects)

Repro

  1. Install cbm 0.8.1 per the official script (single static binary).
  2. Index a repo: codebase-memory-mcp cli index_repository '{"repo_path":"/path/to/MSBA-MSBA"}' — succeeds, list_projects shows it.
  3. Within the same shell session (or the same batch job that called index_repository), run:
    codebase-memory-mcp cli search_graph '{"name_pattern":"DTO$","label":"Class","limit":100,"project":"Users-...-MSBA-MSBA"}'
    → returns 35 results, exit=0.
  4. Wait 10 minutes (or close/reopen the shell).
  5. Run the exact same command again → {"error":"project not found or not indexed", "available_projects":[...the same 4 entries...]}

What's odd

  • list_projects keeps showing the project (full nodes/edges/size_bytes metadata present).
  • _config.db is empty (SELECT * FROM config → 0 rows in ~/.cache/codebase-memory-mcp/_config.db).
  • The per-project SQLite DB (Users-...-MSBA-MSBA.db, ~282 MB) is still on disk, populated, the same content as before — file reports it as a valid SQLite 3.x database.
  • Trying codebase-memory-mcp config set project "<name>" and config reset project does not change anything.
  • Tried 8 variations of the project parameter naming (project, project_name, project_id, projectName, projectPath, root_path) — every form is rejected with the same error.

Smell-test observations from a CI run on 2026-06-29

I ran a 120-combo benchmark (3 tools × 4 repos × 10 probes) using cbm via the same CLI wrapper. During the run (~7 min), all search_graph/query_graph calls inside the bench returned 200-class responses with parsed matches; 5 minutes after the run finished, the exact same CLI invocations started failing.

I noticed two files with display name Users-...-MSBA-MSBA.db in the cache dir, differing only in character class:

inode size path byte sequence
100978290 295895040 ...matias.nah**u**el**.amendola**-Projects-...-MSBA-MSBA.db (note the . after el)
101033163 0 ...matias.nah**u**el**-amendola**-Projects-...-MSBA-MSBA.db (note the - after el)

So list_projects returns 5 entries (one of them is the empty …el-amendola… path), and query_graph "knows about" the populated project (Users-...-MSBA-MSBA.db) but the second …el-amendola… shadow-DB confuses the lookup.

This appears to be a filesystem path normalization issue (Unicode NFD/NFC? Or HFS+'s case-insensitivity creation semantics?) where the CLI picks up a different on-disk file depending on how the path is being passed (env-var vs cmdline-arg vs working-dir-relative), and the wrong one wins.

Probable root cause

The CLI binary must be doing one of:

  1. realpath() on the project argument, then normalizing against an HFS-/APFS-canonical form different from what was used during index time.
  2. Comparing only by display_name (which collides under case-insensitive filesystems) rather than inode/path.
  3. Maintaining an in-memory registry that's only consistent within a single process (the bench's per-process state had the right pointer; subsequent fresh processes have a different one).

Evidence

Bench JSON proving the query path worked once:

  • cbm-MSBA-MSBA-inconsistency_dto_rename.json → 35 matches with qualified_name populated, exit_code=0, command=[...cli, search_graph, '{\"name_pattern\": \"DTO$\", \"label\": \"Class\", \"limit\": 100, \"project\": \"Users-...-MSBA-MSBA\"}']

After the run, the same command returns:

  • exit_code=1, stderr={"error":"project not found or not indexed","hint":"Use list_projects...","available_projects":["...", "...", ..., "Users-...-MSBA-MSBA"]}

What I'd like

A fix (or workaround doc) for one of:

  1. CLI: cache the project registry to disk so it survives process boundaries.
  2. Path normalization: canonicalize project paths the same way at index and query time (suggested: compare by inode/mtime, not path bytes).
  3. Workaround doc: how to invoke cbm CLI so the project lookup is robust against the in-memory-only registry.

Environment

$ codebase-memory-mcp --version
codebase-memory-mcp 0.8.1

$ uname -a
Darwin Mac 24.x ... aarch64

Thanks — happy to test any fix on my end.

Activity

  1. added
    bugSomething isn't working
    cypherCypher query language parser/executor bugs
    ux/behaviorDisplay bugs, docs, adoption UX
    on Jun 30, 2026
  2. DeusData commented on Jun 30, 2026

    @DeusData
    Owner

    Thanks for the detailed report. I’ve triaged this as a project-identity / path-normalization bug: list_projects can still see the DB, but query tools appear to resolve or open a different derived project DB after the original process is gone.

    I’m linking this under the query-resolution and UX trackers. The regression guard should cover: index a project, start a fresh process later, run the same search_graph / query_graph, and verify it opens the populated DB even when a zero-byte shadow DB or APFS-normalized path variant exists. In the meantime, removing the zero-byte shadow DB and re-indexing from one canonical absolute path may be the safest workaround.

  3. added a commit that references this issue on Jun 30, 2026
  4. DeusData commented on Jun 30, 2026

    @DeusData
    Owner

    Fixed in ad422bc (PR #717). Project resolution now keys on the db's INTERNAL project name (the projects.name row), not the .db filename — so list_projects, the resolver, and node queries all agree even when a db's filename drifted from its internal name (the .-vs-- username twin, or a copied/renamed db). Ghost dbs (0-byte/empty) are filtered from the list; no file renames or data mutation. (The empty _config.db you spotted is a red herring — it's a KV settings store, never a registry.) The separate latent bug where queries opened the db read-write — mutating it and failing on a read-only FS — is fixed in #719. Ships next release — thanks for the thorough diagnosis.

  5. DeusData commented on Sep 3, 2026

    @DeusData
    Owner

    A follow-on improvement to the exact symptom reported here landed on main today in f37a47eb (PR #1871, thanks @LazyXuan).

    This issue was about query_graph / search_graph reporting "project not found" while the databases were valid on disk. That message is now gone for the corrupt-store case: a query whose store fails its integrity check reports project store is corrupt (left untouched); run index_repository to rebuild it instead — which says what actually happened and what to do about it, rather than implying the project was never indexed.

    The change underneath it matters too. The query path no longer opens the store writably at all when integrity fails: it closes and reopens through a query-only handle, so a corrupt database is inspected without any possibility of the recovery path quarantining files behind a read-only-looking call. Recording it here in case anyone arrives at this issue from a search.

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 workingcypherCypher query language parser/executor bugsux/behaviorDisplay bugs, docs, adoption UX

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions