{"record":{"id":"795291b6784b4476","repo":"abhigyanpatwari/GitNexus","slug":"gitnexus-failed-to-reclaim-missing-shadow-wal-qua","errorCode":null,"errorMessage":"GitNexus: failed to reclaim missing-shadow WAL quarantines: ${summarizeError(err)}","messagePattern":"GitNexus: failed to reclaim missing-shadow WAL quarantines: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"gitnexus/src/core/lbug/lbug-adapter.ts","lineNumber":860,"sourceCode":"      // Reclaim missing-shadow WAL quarantines from a PRIOR crash (#2637).\n      // LadybugDB renames an unrecoverable WAL aside as\n      // `${dbPath}.wal.missing-shadow.<ts>-<rand>` (quarantineWalForMissingShadow)\n      // instead of deleting it. Once quarantined it is permanently detached from\n      // the live store and never reopened, so reclaiming it is safe regardless of\n      // whether the main DB file exists this run — unlike the orphan-sidecar\n      // cleanup below, this must NOT be gated on \"main DB missing\": a quarantine\n      // event and a healthy main DB are independent facts. Never let a reclaim\n      // failure (e.g. a transient EBUSY from an antivirus scan) block DB startup.\n      if (!sidecarPreflightDisabled()) {\n        try {\n          const reclaimed = await cleanQuarantinedMissingShadowWals(dbPath);\n          for (const file of reclaimed) {\n            logger.warn(\n              `GitNexus: reclaimed quarantined WAL ${path.basename(file)} from a prior crash`,\n            );\n          }\n        } catch (err) {\n          logger.warn(\n            `GitNexus: failed to reclaim missing-shadow WAL quarantines: ${summarizeError(err)}`,\n          );\n        }\n      }\n\n      // Crash-recovery cleanup: if the main DB file is missing, stale sidecars\n      // from an interrupted run can block fresh opens indefinitely.\n      try {\n        await fs.access(dbPath);\n      } catch (err) {\n        if (isMissingFileError(err)) {\n          // `.shadow` is documented by LadybugDB checkpointing and `.wal.checkpoint`\n          // was observed in the #1618 crash loop that motivated this recovery path.\n          const orphanSidecars = [`${dbPath}.shadow`, `${dbPath}.wal.checkpoint`];\n          for (const sidecar of orphanSidecars) {\n            try {\n              await fs.unlink(sidecar);\n              logger.warn(","sourceCodeStart":842,"sourceCodeEnd":878,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/0d1aed942f0e8b5d3bac27519fff441aceea722d/gitnexus/src/core/lbug/lbug-adapter.ts#L842-L878","documentation":"During DB open preflight, GitNexus tried to restore WAL files quarantined by a previous crash (cleanQuarantinedMissingShadowWals) and the reclaim threw. Deliberately non-fatal — a transient EBUSY must not block DB startup — so quarantined WALs stay on disk and any data they held remains unreclaimed until a later run succeeds.","triggerScenarios":"ensureLbugInitialized opens a DB whose directory contains quarantined WAL files from a prior crash; the reclaim (rename/copy back) fails with EBUSY, EACCES, EXDEV, or an I/O error. The code explicitly notes antivirus scans as a known transient source.","commonSituations":"Windows machines with real-time antivirus scanning the .gitnexus directory right at open; quarantined files on network/EXDEV layouts; runs immediately after a crashed process whose handles the OS has not released; permission drift after container restarts.","solutions":["Simply retry the analyze/serve run — transient EBUSY typically clears and the next preflight reclaims successfully.","Add the repo's .gitnexus directory to antivirus exclusions (the code calls this scenario out by name).","If it persists, inspect the quarantine sidecar files next to the DB and restore/remove them manually while nothing else runs.","As a diagnostic escape hatch only, GITNEXUS_DISABLE_LBUG_SIDECAR_PREFLIGHT=1 skips preflight — use it to confirm the diagnosis, not as a permanent fix."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Reclaim failure is transient-tolerant by design: retry the open\nfor (let attempt = 1; attempt <= 3; attempt++) {\n  try { return await initLbug(dbPath); }\n  catch (err) {\n    if (attempt === 3 || !isTransientFsError(err)) throw err;\n    await sleep(500 * attempt); // EBUSY from AV scans usually clears\n  }\n}","preventionTips":["Exclude the .gitnexus directory from real-time antivirus scanning.","Do not kill -9 gitnexus mid-analyze; graceful stops leave fewer quarantines to reclaim.","Retry analyze after a crash before assuming corruption."],"tags":["ladybugdb","wal","crash-recovery","ebusy","windows","antivirus"],"backgroundTag":"wal-recovery-failed","analyzedSha":"0d1aed942f0e8b5d3bac27519fff441aceea722d","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}