{"record":{"id":"a6304fbd015e78f7","repo":"abhigyanpatwari/GitNexus","slug":"auto-sync-run-cancelled","errorCode":null,"errorMessage":"Auto-sync run cancelled.","messagePattern":"Auto-sync run cancelled\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"gitnexus/src/core/auto-sync/runner.ts","lineNumber":505,"sourceCode":"      nextIndex += 1;\n      results[currentIndex] = await worker(items[currentIndex]);\n      throwIfAborted(signal);\n    }\n  });\n  // Settle every runner before surfacing a failure. Promise.all rejects on the\n  // first error while siblings are still inside a clone or waiting on an\n  // analyze fork, and the caller treats that rejection as \"the run is over\" —\n  // it releases the watch mutex and exits, orphaning those children. Each\n  // runner already refuses new work at the abort check above, so waiting here\n  // costs nothing on the cancel path.\n  const settlements = await Promise.allSettled(runners);\n  const failure = settlements.find((s) => s.status === 'rejected');\n  if (failure) throw (failure as PromiseRejectedResult).reason;\n  return results;\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n  if (signal?.aborted) throw new Error('Auto-sync run cancelled.');\n}\n\ninterface AutoSyncWorkItem {\n  project: AutoSyncProjectConfig;\n  remoteUrl: string;\n  cloneRoot?: Awaited<ReturnType<typeof resolveConfiguredCloneRoot>>;\n  repoName?: string;\n  targetDir?: string;\n  error?: string;\n}\n\nasync function syncFirstAvailableBranch(input: {\n  item: AutoSyncWorkItem;\n  repoName: string;\n  targetDir: string;\n  timeoutMs: number;\n  deps: AutoSyncRunDeps;\n  logger: AutoSyncLogger;","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/0d1aed942f0e8b5d3bac27519fff441aceea722d/gitnexus/src/core/auto-sync/runner.ts#L487-L523","documentation":"throwIfAborted raises a plain Error('Auto-sync run cancelled.') when the AbortSignal passed to an auto-sync run has fired. runAutoSyncOnce, repoResults, and the per-item runners check it at cancellation points so an aborted run stops promptly instead of continuing work.","triggerScenarios":"Calling runAutoSyncOnce (or its internals repoResults/runners) with an AbortSignal that is already aborted, or aborting the signal mid-run at a checkpoint.","commonSituations":"User presses Ctrl-C / cancels a long auto-sync run from the UI; a timeout wrapper aborts the signal; a shutdown hook aborts pending sync work.","solutions":["Treat this error as expected control flow: catch it and skip cleanup-as-failure reporting.","Re-run the auto-sync with a fresh, non-aborted AbortSignal (and a longer timeout if applicable).","If you did not intend cancellation, check what is aborting the signal (timeout, signal handler) before retrying."],"exampleFix":"// before\nawait runAutoSyncOnce(config, signal); // crashes reporting as error\n\n// after\ntry {\n  await runAutoSyncOnce(config, signal);\n} catch (err) {\n  if (signal?.aborted) return; // expected cancellation\n  throw err;\n}","handlingStrategy":"try-catch","validationCode":"if (signal?.aborted) return; // skip the run entirely before starting","typeGuard":null,"tryCatchPattern":"try {\n  await runAutoSyncOnce(config, signal);\n} catch (err) {\n  if (err instanceof Error && err.message === 'Auto-sync run cancelled.') return; // expected\n  throw err;\n}","preventionTips":["Check signal.aborted before launching a run.","Use AbortSignal.timeout() deliberately and size the timeout to the workload.","Never route genuine failures through the same signal you use for cancellation."],"tags":["cancellation","abort-signal","auto-sync","control-flow"],"backgroundTag":"operation-cancelled","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"}