{"record":{"id":"806822f443537509","repo":"abhigyanpatwari/GitNexus","slug":"ladybugdb-unavailable-for-repoid-another-proce","errorCode":null,"errorMessage":"LadybugDB unavailable for ${repoId}. Another process may be rebuilding the index. Retry later. (${lastError?.message || 'unknown error'})","messagePattern":"LadybugDB unavailable for (.+?)\\. Another process may be rebuilding the index\\. Retry later\\. \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/lbug/pool-adapter.ts","lineNumber":799,"sourceCode":"        if (\n          lastError.message.startsWith('LadybugDB checkpoint sidecar is missing') ||\n          lastError.message.startsWith('LadybugDB checkpoint sidecar is present but unreachable') ||\n          lastError.message.startsWith('GitNexus could not move the LadybugDB WAL sidecar') ||\n          isMissingShadowSidecarError(lastError)\n        ) {\n          throw lastError;\n        }\n\n        const isLockError =\n          lastError.message.includes('Could not set lock') ||\n          /\\block(\\b|ed|ing)/i.test(lastError.message);\n        if (!isLockError || attempt === LOCK_RETRY_ATTEMPTS) break;\n        await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_DELAY_MS * attempt));\n      }\n    }\n\n    if (!shared) {\n      throw new Error(\n        `LadybugDB unavailable for ${repoId}. Another process may be rebuilding the index. ` +\n          `Retry later. (${lastError?.message || 'unknown error'})`,\n      );\n    }\n  }\n\n  shared.refCount++;\n  const db = shared.db;\n\n  // Pre-create the full pool upfront so createConnection() (which silences\n  // stdout) is never called lazily during active query execution.\n  // Mark preWarmActive so the watchdog timer doesn't interfere.\n  preWarmActive = true;\n  const available: lbug.Connection[] = [];\n  try {\n    for (let i = 0; i < MAX_CONNS_PER_REPO; i++) {\n      available.push(createConnection(db));\n    }","sourceCodeStart":781,"sourceCodeEnd":817,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/52924ef12c2290ceee4612526a828ec4cdf2047f/gitnexus/src/core/lbug/pool-adapter.ts#L781-L817","documentation":"doInitLbug (gitnexus/src/core/lbug/pool-adapter.ts:794): after LOCK_RETRY_ATTEMPTS lock-busy retries — or an open failure that is neither WAL corruption, sidecar-classified, nor lock-busy — no shared Database could be opened. The trailing parenthesized message is the last underlying error; the typical cause is a concurrent writer holding the database lock.","triggerScenarios":"initLbug while `gitnexus analyze` (or another serve/MCP instance in write mode) holds the database lock longer than the retry budget; or any open error with no dedicated recovery path (the lastError text says which).","commonSituations":"Starting an MCP session or serve during a long incremental analyze; several CI jobs opening the same mounted storage simultaneously.","solutions":["Retry once the concurrent analyze finishes — the message says exactly that","Stagger schedules so serve/MCP startup does not race analyze on the same repo","Read the trailing lastError: if it is not lock-shaped, fix that underlying issue (path, permissions)","Never write from MCP/serve — keep writers to analyze so the read-only pool rarely contends"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// before opening, check whether another writer holds the index (lock file present + alive)\nimport { readFile } from 'node:fs/promises';\nconst lockPid = await readFile(`${dbPath}.lock`, 'utf8').then(\n  (s) => s.trim(),\n  () => '',\n);\nif (lockPid && (await isProcessAlive(Number(lockPid)))) {\n  throw new Error('analyze in progress — defer pool init');\n}","typeGuard":"const isLbugUnavailable = (e: unknown): boolean =>\n  e instanceof Error && e.message.startsWith('LadybugDB unavailable for');","tryCatchPattern":"let lastErr: unknown;\nfor (let attempt = 0; attempt < 5; attempt++) {\n  try {\n    await initLbug(repoId, dbPath);\n    break;\n  } catch (e) {\n    lastErr = e;\n    if (!isLbugUnavailable(e)) throw e;\n    await sleep(10_000 * (attempt + 1)); // back off while the rebuild finishes\n  }\n}\nif (lastErr) throw lastErr;","preventionTips":["Schedule serve/MCP startup to wait for a running analyze instead of racing it","Keep exactly one writer (analyze) per repository; all readers use the read-only pool","Read the trailing lastError — non-lock causes need different fixes than waiting"],"tags":["gitnexus","ladybugdb","lock","retry-exhausted","concurrency"],"backgroundTag":"database-locked","analyzedSha":"52924ef12c2290ceee4612526a828ec4cdf2047f","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}