{"record":{"id":"3dc660583efbe207","repo":"abhigyanpatwari/GitNexus","slug":"message","errorCode":null,"errorMessage":"${message}","messagePattern":"\\$\\{message\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"gitnexus/src/storage/index-lock.ts","lineNumber":185,"sourceCode":"  /** Present only for acquisition/reclaim guard contention, requiring quiesced recovery. */\n  readonly guardPath?: string;\n  constructor(holder: LockRecord, waitedMs: number, holderKnown = true, guardPath?: string) {\n    super(formatIndexLockTimeoutMessage(holder, waitedMs, holderKnown, guardPath));\n    this.name = 'IndexLockTimeoutError';\n    this.holder = holder;\n    this.holderKnown = holderKnown;\n    this.guardPath = guardPath;\n  }\n}\n\nexport const isIndexLockGuardTimeout = (\n  error: unknown,\n): error is IndexLockTimeoutError & { guardPath: string } =>\n  error instanceof IndexLockTimeoutError && error.guardPath !== undefined;\n\n/** Writers must refuse a handle that does not own the lock. */\nexport const requireExclusiveIndexLock = (handle: IndexLockHandle, message: string): void => {\n  if (handle.lockFree) throw new Error(message);\n};\n\nconst formatIndexLockTimeoutMessage = (\n  holder: LockRecord,\n  waitedMs: number,\n  holderKnown: boolean,\n  guardPath?: string,\n): string => {\n  if (guardPath !== undefined) {\n    return (\n      `Timed out after ${waitedMs}ms waiting for acquisition/reclaim guard ${guardPath}. ` +\n      `Quiesce all relevant writers and prevent restart before manual recovery. ` +\n      `Never remove the guard while writers may run; see RUNBOOK.md for quiesced recovery.`\n    );\n  }\n  if (holderKnown) {\n    return (\n      `Timed out after ${waitedMs}ms waiting for another gitnexus analyze ` +","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/ac9a4e9abd8fd3058c070b72c23402a4f887929a/gitnexus/src/storage/index-lock.ts#L167-L203","documentation":"An `IndexLockHandle` acquired for read-only or shared use reports `lockFree === true`, meaning the caller does not actually own the exclusive index lock. `requireExclusiveIndexLock` is a guard for mutating operations: it throws the supplied message rather than letting a writer proceed against an index it does not have exclusive access to, which would corrupt the storage.","triggerScenarios":"Code calls `requireExclusiveIndexLock(handle, msg)` with a handle obtained from a non-exclusive (shared/read-only) lock acquisition, or a handle whose lock has already been released (`lockFree` true), before performing an index write/mutation such as analyze writeback or compaction.","commonSituations":"A code path acquired the lock with the shared/read-only API but then reached a write routine; the lock was released early (early return / error path) and the stale handle was still passed on; refactoring changed which handle flows into a writer without updating the acquisition mode.","solutions":["Acquire the index lock in exclusive (write) mode before the mutating operation and pass that handle to the writer.","Ensure the lock is still held (not yet released) at the call site; reorder release to after the write completes.","Audit the handle's origin — if only a shared handle is available, either upgrade the acquisition or make the operation read-only.","Use a try/finally pattern so the exclusive handle is released exactly once, after `requireExclusiveIndexLock` and the write succeed or fail."],"exampleFix":"// before: read-only handle handed to a writer\nconst handle = await acquireSharedIndexLock(dir);\nrequireExclusiveIndexLock(handle, 'write requires exclusive lock'); // throws: lockFree\n// after\nconst handle = await acquireExclusiveIndexLock(dir);\ntry {\n  requireExclusiveIndexLock(handle, 'write requires exclusive lock');\n  await writeToIndex(dir);\n} finally {\n  handle.release();\n}","handlingStrategy":"type-guard","validationCode":"// verify ownership before any write\nif (!handle || handle.lockFree) {\n  throw new Error('Attempt to write with a non-exclusive or released index lock handle');\n}","typeGuard":"const holdsExclusiveLock = (handle) =>\n  handle != null && handle.lockFree === false;","tryCatchPattern":"try {\n  requireExclusiveIndexLock(handle, 'write requires an exclusive index lock');\n  await writeToIndex(dir);\n} catch (e) {\n  // reacquire the lock in exclusive mode and retry once\n  const fresh = await acquireExclusiveIndexLock(dir);\n  try { await writeToIndex(dir); } finally { fresh.release(); }\n}","preventionTips":["Pair every index write with an exclusive-mode acquisition in the same function.","Release locks in try/finally so a handle is never used after release.","Type-sign write helpers to accept only the exclusive handle type, not the shared one.","Keep lock acquisition and release in one scope to avoid stale-handle reuse after refactors."],"tags":["locking","index","invariant","concurrency"],"backgroundTag":"internal-invariant-violation","analyzedSha":"ac9a4e9abd8fd3058c070b72c23402a4f887929a","analyzedAt":"2026-09-15T23:29:44.066Z","contentChangedAt":"2026-09-15T23:29:44.066Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}