{"record":{"id":"4c1a1f236e139898","repo":"abhigyanpatwari/GitNexus","slug":"unable-to-re-arm-the-filesystem-watcher","errorCode":null,"errorMessage":"Unable to re-arm the filesystem watcher","messagePattern":"Unable to re-arm the filesystem watcher","errorType":"exception","errorClass":"WatchControlReloadError","httpStatus":null,"severity":"error","filePath":"gitnexus/src/cli/analyze-watch.ts","lineNumber":367,"sourceCode":"  // rescan would emit, an immediate rewrite of that file is dropped for good\n  // (reproduced on chokidar 4 and 5). So re-arm by arming a replacement\n  // watcher and awaiting its `ready` instead. The outgoing instance keeps\n  // reporting until the replacement is armed, so the swap has no blind window,\n  // and a replacement that fails to arm leaves the working instance in place.\n  const rearmWatcher = async (): Promise<void> => {\n    rearmPending = false;\n    if (closed) return;\n    const replacement = createWatcher();\n    try {\n      await waitUntilReady(replacement);\n    } catch (error) {\n      rearmPending = true;\n      try {\n        await replacement.close();\n      } catch {\n        // The instance never became live; the arm error is the one to report.\n      }\n      throw new WatchControlReloadError(\n        new Error('Unable to re-arm the filesystem watcher', { cause: error }),\n      );\n    }\n    const retired = watcher;\n    watcher = replacement;\n    await retired.close();\n    // `close()` can land between arming the replacement and the swap above.\n    if (closed) await replacement.close();\n  };\n\n  try {\n    await waitUntilReady(watcher);\n    await queue.runInitial();\n  } catch (error) {\n    closed = true;\n    await watcher.close();\n    await queue.close();\n    throw error;","sourceCodeStart":349,"sourceCodeEnd":385,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/0d1aed942f0e8b5d3bac27519fff441aceea722d/gitnexus/src/cli/analyze-watch.ts#L349-L385","documentation":"rearmWatcher() replaces the fs watcher when re-arming is pending. If creating/starting the replacement watcher itself throws, it closes the half-built replacement and throws a WatchControlReloadError with 'Unable to re-arm the filesystem watcher', with the original error as cause. Watch mode cannot continue without a live watcher.","triggerScenarios":"The watch directory or its parent was deleted/renamed mid-watch, the OS hit EMFILE/ENOSPC (too many open files / inotify watch limit), or permission on the watched directory changed.","commonSituations":"Long-running watch sessions in containers hitting the inotify limit (fs.inotify.max_user_watches), branch checkouts that rename the repo directory, or resource exhaustion on CI.","solutions":["Restart `gitnexus analyze --watch` from the restored directory after fixing the underlying cause.","Raise the inotify limit: sudo sysctl fs.inotify.max_user_watches=524288 (Linux).","Raise the open-file limit: ulimit -n 4096 or the container equivalent.","Verify the repo path still exists and is readable; re-clone or re-checkout if it was moved."],"exampleFix":"// before\nsysctl fs.inotify.max_user_watches  # 8192 -> EMFILE/ENOSPC\n// after\nsudo sysctl -w fs.inotify.max_user_watches=524288\ngitnexus analyze --watch","handlingStrategy":"retry","validationCode":"const fs = require('fs');\nif (!fs.existsSync(repoPath)) throw new Error('repo path missing before watch');\nif (process.platform === 'linux' && Number(readInotifyLimit()) < 8192) console.warn('raise fs.inotify.max_user_watches');","typeGuard":null,"tryCatchPattern":"try {\n  await runWatch();\n} catch (e) {\n  if (e instanceof WatchControlReloadError && /re-arm the filesystem watcher/.test(e.message)) {\n    await sleep(1000);\n    return runWatch(); // retry after transient EMFILE/ENOSPC\n  }\n  throw e;\n}","preventionTips":["Raise fs.inotify.max_user_watches on Linux before long watch sessions","Raise the open-file ulimit in containers/CI","Don't move or rename the repo directory while watch is running"],"tags":["watch-mode","filesystem","inotify","resource-limits"],"backgroundTag":"network-request-failed","analyzedSha":"0d1aed942f0e8b5d3bac27519fff441aceea722d","analyzedAt":"2026-09-08T00:40:44.970Z","contentChangedAt":"2026-09-08T00:40:44.970Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}