{"record":{"id":"de5196a96776d161","repo":"abhigyanpatwari/GitNexus","slug":"watch-refresh-is-already-running","errorCode":null,"errorMessage":"Watch refresh is already running","messagePattern":"Watch refresh is already running","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitnexus/src/cli/watch-queue.ts","lineNumber":68,"sourceCode":"      this.pending.add(filePath);\n    } else {\n      this.overflowed = true;\n      if (priority) {\n        const evictable = [...this.pending].find(\n          (pendingPath) => this.options.isPriorityPath?.(pendingPath) !== true,\n        );\n        if (evictable !== undefined) {\n          this.pending.delete(evictable);\n          this.pending.add(filePath);\n        }\n      }\n    }\n  }\n\n  /** Run the initial refresh while still queueing events that arrive during it. */\n  async runInitial(): Promise<void> {\n    if (this.closed) return;\n    if (this.active !== undefined) throw new Error('Watch refresh is already running');\n    try {\n      await this.runBatch([], true);\n    } finally {\n      this.initialPending = false;\n      if (!this.closed && this.hasPendingWork()) this.schedule();\n      else this.resolveIdleWaiters();\n    }\n  }\n\n  async waitForIdle(): Promise<void> {\n    if (this.isIdle()) return;\n    await new Promise<void>((resolve) => this.idleWaiters.add(resolve));\n  }\n\n  async close(): Promise<void> {\n    this.closed = true;\n    if (this.timer !== undefined) clearTimeout(this.timer);\n    this.timer = undefined;","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/52924ef12c2290ceee4612526a828ec4cdf2047f/gitnexus/src/cli/watch-queue.ts#L50-L86","documentation":"Thrown by WatchQueue.runInitial in watch-queue.ts when the initial `analyze --watch` refresh is requested while another refresh batch is already active. runInitial is meant to be the first, exclusive refresh; the queue serializes all refreshes, so a concurrent one is a programming error by the caller, not a recoverable condition.","triggerScenarios":"Calling watchQueue.runInitial() while `this.active` is set — e.g. calling runInitial twice, or calling it after event-driven refreshes have already started, or concurrently from two async tasks before the first await resolves the batch.","commonSituations":"Custom tooling wrapping the watch mode that re-invokes runInitial on a timer or file event; race conditions when starting the watcher and queueing events at nearly the same time; tests that construct a shared queue and call runInitial from multiple cases.","solutions":["Call runInitial() exactly once per WatchQueue, before any events are scheduled, and await it before proceeding.","Guard the call with the queue's own state: only invoke when no refresh is active (or track a local `started` flag).","For subsequent refreshes, rely on the queue's event scheduling (`schedule()` / pending work) instead of calling runInitial again.","If you need to re-run after a failure, close and recreate the WatchQueue rather than re-calling runInitial."],"exampleFix":"// before\nawait queue.runInitial();\nwatcher.on('change', () => queue.runInitial()); // throws on overlap\n\n// after\nawait queue.runInitial(); // once, at startup\nwatcher.on('change', () => queue.enqueue(changedPath)); // queue serializes the rest","handlingStrategy":"try-catch","validationCode":"if (queue.hasActiveRefresh?.()) {\n  throw new Error('skip: initial refresh already in progress');\n}\n// or track locally: let initialDone = false; only call runInitial when !initialDone","typeGuard":null,"tryCatchPattern":"try {\n  await queue.runInitial();\n  initialDone = true;\n} catch (e) {\n  if (e.message === 'Watch refresh is already running') {\n    // another refresh owns the queue; wait for idle instead of retrying\n    await queue.waitForIdle();\n  } else throw e;\n}","preventionTips":["Call runInitial exactly once at watcher startup and await it before wiring event handlers.","Route all later refresh requests through the queue's enqueue/schedule API, never runInitial.","Await the previous runInitial before any code path that could trigger another."],"tags":["watch-mode","concurrency","state-error","cli"],"backgroundTag":"operation-already-running","analyzedSha":"52924ef12c2290ceee4612526a828ec4cdf2047f","analyzedAt":"2026-09-01T13:15:02.810Z","contentChangedAt":"2026-09-01T13:15:02.810Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}