{"record":{"id":"4e055a87a742d560","repo":"thedotmack/claude-mem","slug":"hard-cap-exceeded-activecount-processes-in-reg","errorCode":null,"errorMessage":"Hard cap exceeded: ${activeCount} processes in registry (cap=${TOTAL_PROCESS_HARD_CAP}). Refusing to spawn more.","messagePattern":"Hard cap exceeded: (.+?) processes in registry \\(cap=(.+?)\\)\\. Refusing to spawn more\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/supervisor/process-registry.ts","lineNumber":549,"sourceCode":"\nfunction notifySlotAvailable(): void {\n  const waiter = slotWaiters.shift();\n  if (waiter) waiter();\n}\n\n/**\n * Waits until an SDK agent slot is free, then reserves it. The count check\n * and the reservation happen in the same synchronous block, so no concurrent\n * caller can be granted the same slot. The caller must release the returned\n * reservation once the spawned process is registered (the registry record\n * takes over the accounting) or when the spawn fails or never happens:\n * a leaked reservation would occupy the slot until the worker restarts.\n */\nexport async function waitForSlot(maxConcurrent: number, signal?: AbortSignal): Promise<SlotReservation> {\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 < maxConcurrent) 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}/${maxConcurrent}), 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 cleanup = () => {\n      if (recheckTimer) clearInterval(recheckTimer);\n      if (abortHandler && signal) signal.removeEventListener('abort', abortHandler);\n      const idx = slotWaiters.indexOf(onSlot);\n      if (idx >= 0) slotWaiters.splice(idx, 1);","sourceCodeStart":531,"sourceCodeEnd":567,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d768ba364302d12b76e69e4f021f0bb1d2d50ed6/src/supervisor/process-registry.ts#L531-L567","documentation":"Error \"Hard cap exceeded: ${activeCount} processes in registry (cap=${TOTAL_PROCESS_HARD_CAP}). Refusing to spawn more.\" thrown in thedotmack/claude-mem.","triggerScenarios":"Fires when the process registry already holds TOTAL_PROCESS_HARD_CAP live entries and another spawn is requested, typically from a runaway hook loop, repeated failing session spawns, or leaked processes that were never reaped. The hard cap at src/supervisor/process-registry.ts:549 stops resource exhaustion before the host is overwhelmed.","commonSituations":"See trigger scenarios.","solutions":["Wait for running processes to exit or kill stale ones so the registry count drops below TOTAL_PROCESS_HARD_CAP, then retry.","Investigate process leaks: pruneDeadEntries() already ran, so surviving entries are live processes — find what is spawning them and add limits."],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"d768ba364302d12b76e69e4f021f0bb1d2d50ed6","analyzedAt":"2026-08-12T23:52:55.241Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}