{"record":{"id":"5517dc743a79f858","repo":"thedotmack/claude-mem","slug":"waitforslot-aborted-before-queuing","errorCode":null,"errorMessage":"waitForSlot aborted before queuing","messagePattern":"waitForSlot aborted before queuing","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/supervisor/process-registry.ts","lineNumber":577,"sourceCode":" * mid-response.\n */\nexport async function waitForSlot(\n  maxConcurrent: number | (() => number),\n  signal?: AbortSignal,\n  sessionId?: number | string\n): Promise<SlotReservation> {\n  const getMax = typeof maxConcurrent === 'function' ? maxConcurrent : () => maxConcurrent;\n\n  getProcessRegistry().pruneDeadEntries();\n  const activeCount = getActiveSdkCount();\n  if (activeCount >= TOTAL_PROCESS_HARD_CAP) {\n    throw new Error(`Hard cap exceeded: ${activeCount} processes in registry (cap=${TOTAL_PROCESS_HARD_CAP}). Refusing to spawn more.`);\n  }\n\n  if (activeCount < getMax()) return takeSlotReservation();\n\n  if (signal?.aborted) {\n    throw new Error('waitForSlot aborted before queuing');\n  }\n\n  logger.info('PROCESS', `Pool limit reached (${activeCount}/${getMax()}), waiting for slot...`);\n\n  return new Promise<SlotReservation>((resolve, reject) => {\n    let recheckTimer: ReturnType<typeof setInterval> | null = null;\n    let abortHandler: (() => void) | null = null;\n    const record: SlotWaiterRecord = {\n      sessionId,\n      parkedSince: Date.now(),\n      warnedParked: false,\n      notify: () => {},\n    };\n    const cleanup = () => {\n      if (recheckTimer) clearInterval(recheckTimer);\n      if (abortHandler && signal) signal.removeEventListener('abort', abortHandler);\n      const idx = slotWaiters.indexOf(record);\n      if (idx >= 0) slotWaiters.splice(idx, 1);","sourceCodeStart":559,"sourceCodeEnd":595,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/supervisor/process-registry.ts#L559-L595","documentation":"waitForSlot accepts an optional AbortSignal and checks it before joining the waiting queue. If the signal is already aborted when the caller would otherwise have to wait (pool full), the call throws immediately rather than queueing a promise that would be rejected anyway. Fast-fails work that was cancelled before it even started waiting.","triggerScenarios":"Calling waitForSlot with an AbortSignal that is already aborted while the pool is full (activeCount >= max), so the pre-queue abort check fires.","commonSituations":"Request cancellation (HTTP client disconnect) completed before slot acquisition; timeouts that abort the signal earlier in the pipeline; reusing an aborted controller for a second spawn attempt.","solutions":["Check signal.aborted before attempting the spawn and skip cancelled work","Create a fresh AbortController per spawn attempt instead of reusing one","Order operations so the abort signal is only created when the work is actually starting"],"exampleFix":"// before\nawait waitForSlot(max, reusedSignal); // reusedSignal already aborted\n// after\nconst controller = new AbortController();\nif (!controller.signal.aborted) {\n  await waitForSlot(max, controller.signal);\n}","handlingStrategy":"try-catch","validationCode":"if (signal?.aborted) return; // skip cancelled work before requesting a slot","typeGuard":"function isAborted(signal?: AbortSignal): boolean { return signal?.aborted === true; }","tryCatchPattern":"try { const slot = await waitForSlot(max, signal); }\ncatch (e) { if (e.message === 'waitForSlot aborted before queuing') return; /* cancelled, not an error */ throw e; }","preventionTips":["Create a fresh AbortController per spawn attempt","Check signal.aborted at the start of the async workflow","Distinguish cancellation from failure in error handling"],"tags":["async","abort","backpressure"],"backgroundTag":"operation-aborted","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}