abhigyanpatwari/GitNexus · warning
GitNexus [query:vector]: vector index query failed; using…
Error message
GitNexus [query:vector]: vector index query failed; using exact scan fallback
What it means
The vector (ANN) index query in the MCP query tool's semantic path failed; bestChunks is reset to an empty Map and the code falls back to a brute-force exact scan. The diagnostic fires once per LocalBackend instance (warnedVectorUnsupported) to keep stderr quiet on hot paths. The fallback has its own ceiling: when the embedding count exceeds getExactScanLimit(), the exact scan returns [] rather than scanning.
Solutions
- Re-run analyze with a current version so embeddings and the vector index are built.
- Check the single warn at first fallback — its err names the actual engine reason (extension vs corruption).
- If results come back empty on a large DB, suspect the exact-scan limit: rebuild embeddings so the ANN path works instead of relying on the capped fallback.
- Ensure the MCP server process loads the same LadybugDB build (with vector extension) as the CLI that indexed.
Defensive patterns
Strategy: fallback
Validate before calling
// Before semantic search at scale: check embedding count vs the exact-scan limit
const cnt = await countEmbeddings(repo.lbugPath);
if (cnt > getExactScanLimit()) {
await ensureVectorIndex(repo.lbugPath); // rebuild so ANN works; exact scan would return []
} Try / catch
try {
bestChunks = await vectorIndexQuery(queryVec, k);
} catch (err) {
bestChunks = new Map(); // exact-scan fallback path
warnOnce(err); // first failure only — avoid noisy hot-path stderr
if (embeddingCount > exactLimit) return []; // fallback ceiling: too big to brute-force
} Prevention
- Rebuild embeddings (analyze with a current version) so the ANN index exists.
- Watch for the once-per-instance warn at query time — it is the only visible clue of permanent fallback.
- Remember the exact-scan fallback silently returns [] above getExactScanLimit() — size accordingly.
When it happens
Trigger: A semantic query runs; the vector-index query over the EMBEDDING table throws — LadybugDB build without the vector extension, index missing on a DB from before embeddings, or a corrupted index. First occurrence warns with the underlying err; later occurrences are silent for that instance.
Common situations: DBs indexed before embedding support or with embeddings disabled; MCP processes with a LadybugDB lacking vector extensions; very large embedding tables where the exact-scan limit then empties results entirely.
Related errors
- deleteNodesForFile: table does not exist — skipping…
- deleteNodesForFiles: table does not exist — skipping…
- [embed] could not count persisted embeddings; leaving…
- [embed] Failed to delete stale embedding rows — aborting to…
- GitNexus: BM25/FTS search failed (FTS indexes may not…
AI-assisted analysis of abhigyanpatwari/GitNexus@ac9a4e9abd (2026-08-20).
Data as JSON: /api/errors/dda8f0f37f85e9f8.
Report an issue: GitHub.
Appendix: source
Thrown at gitnexus/src/mcp/local/local-backend.ts:3526
const nodeIds = bm25Result.nodeIds?.length ? bm25Result.nodeIds : null;
const symbols = nodeIds
? await executeParameterized(
repo.lbugPath,
`
MATCH (n)
WHERE n.id IN $nodeIds
RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine
ORDER BY startLine, id
`,
{ nodeIds },
)
: await executeParameterized(
repo.lbugPath,
// Same BasicBlock exclusion as detect_changes (#2082 U7): on a
// --pdg index a function-heavy file has far more BasicBlock rows
// than symbols, so an unfiltered LIMIT 3 would surface nameless
// substrate rows and displace the real symbols.
`
MATCH (n)
WHERE n.filePath = $filePath
AND NOT n.id STARTS WITH 'BasicBlock:'
RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine
ORDER BY startLine, id
LIMIT 3
`,
{ filePath: fullPath },
);
if (symbols.length > 0) {
for (const sym of symbols) {
results.push({
nodeId: sym.id || sym[0],
name: sym.name || sym[1],
type: sym.type || sym[2],
filePath: sym.filePath || sym[3],
// Raw 0-based here — `bm25Search` is only called from `query()`,View on GitHub (pinned to ac9a4e9abd)