{"record":{"id":"56d2cda559f9234a","repo":"abhigyanpatwari/GitNexus","slug":"gitnexus-unable-to-acquire-init-lock-after-init","errorCode":null,"errorMessage":"GitNexus: unable to acquire init lock after ${INIT_LOCK_MAX_ATTEMPTS} attempts — another gitnexus process may be initializing the same database (${lockPath})","messagePattern":"GitNexus: unable to acquire init lock after (.+?) attempts — another gitnexus process may be initializing the same database \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/lbug/lbug-adapter.ts","lineNumber":431,"sourceCode":"            logger.warn(\n              `GitNexus: failed to release init lock (${code ?? 'UNKNOWN'}): ${summarizeError(err)}`,\n            );\n          }\n        }\n      };\n    } catch (err) {\n      if ((err as NodeJS.ErrnoException)?.code !== 'EEXIST') {\n        throw err; // Unexpected error — propagate immediately\n      }\n\n      // Lock file exists — check if it's stale\n      const broken = await tryBreakStaleLock(lockPath);\n      if (broken && attempt < INIT_LOCK_MAX_ATTEMPTS) {\n        continue; // Stale lock removed — retry immediately\n      }\n\n      if (attempt === INIT_LOCK_MAX_ATTEMPTS) {\n        throw new Error(\n          `GitNexus: unable to acquire init lock after ${INIT_LOCK_MAX_ATTEMPTS} attempts — ` +\n            `another gitnexus process may be initializing the same database (${lockPath})`,\n        );\n      }\n\n      // Live process holds the lock — wait and retry\n      await new Promise((resolve) => setTimeout(resolve, INIT_LOCK_RETRY_DELAY_MS));\n    }\n  }\n\n  // Unreachable — loop always throws or returns\n  throw new Error('GitNexus: init lock acquisition failed unexpectedly');\n};\n\n/** Exported for testing — returns the lock file path for a given dbPath. */\nexport const _initLockPathForTest = initLockPath;\n\nconst runWithSessionLock = async <T>(operation: () => Promise<T>): Promise<T> => {","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/ac9a4e9abd8fd3058c070b72c23402a4f887929a/gitnexus/src/core/lbug/lbug-adapter.ts#L413-L449","documentation":"The init lock in lbug-adapter.ts serializes database initialization with an exclusive lock file: up to INIT_LOCK_MAX_ATTEMPTS (6) attempts spaced INIT_LOCK_RETRY_DELAY_MS (500ms) apart, breaking stale locks between attempts. If a live process still holds the lock after ~3 seconds, this error reports that another GitNexus process is probably initializing the same database, naming the lock path.","triggerScenarios":"Running `gitnexus analyze` (or any DB-opening command) concurrently with a `gitnexus serve`/MCP process that is initializing the same index; two CLI invocations racing on a shared GITNEXUS_HOME storage dir; parallel CI jobs sharing a cache volume; or a leftover lock file that tryBreakStaleLock did not consider stale.","commonSituations":"IDE MCP server auto-starting while the user runs the CLI on the same repo; CI matrix jobs sharing an index volume; a previous crash leaving a lock whose PID/heuristics still look live.","solutions":["Wait for the in-flight process to finish initializing, then re-run the command","Stop the concurrent process (gitnexus serve / MCP server) that holds the lock, then retry","If you can verify no other GitNexus process is running, remove the lock file at the path named in the message","Serialize writers: ensure only one process initializes a given database at a time (one analyze, or one serve, per repo/storage dir)"],"exampleFix":"# before: two processes race\n$ gitnexus serve & gitnexus analyze .\n# after: stop the server first, then initialize\n$ gitnexus mcp stop   # or kill the serve process\ngitnexus analyze .\ngitnexus serve &","handlingStrategy":"retry","validationCode":"import fs from 'node:fs';\n\nconst lockPath = getLockPath(dbPath); // same path the adapter names in the error\ntry {\n  fs.accessSync(lockPath);\n  console.error(`Init lock present at ${lockPath} — another gitnexus process may be initializing; wait or stop it.`);\n  process.exit(1);\n} catch {\n  /* no lock — safe to proceed */\n}\nawait openDatabase(dbPath);","typeGuard":null,"tryCatchPattern":"try {\n  await withLbugDb(dbPath, run);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('unable to acquire init lock')) {\n    // wait for the concurrent initializer to finish (or stop it), verify no gitnexus process runs,\n    // optionally delete the lock file named in the message, then retry once\n  }\n  throw err;\n}","preventionTips":["Serialize database initialization per storage dir: one writer (analyze or serve/MCP) at a time","In CI, guard shared index volumes with a job-level mutex so matrix jobs don't race the init lock","If a run was killed, check for and clear leftover lock files before the next run"],"tags":["locking","concurrency","initialization","ladybugdb","file-lock"],"backgroundTag":"file-lock-contention","analyzedSha":"ac9a4e9abd8fd3058c070b72c23402a4f887929a","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}