thedotmack/claude-mem · error · Error

Supervisor is shutting down, refusing to spawn

Error message

Supervisor is shutting down, refusing to spawn ${type}

What it means

assertCanSpawn is the supervisor's shutdown gate: once stop() has been initiated (stopPromise is non-null), no new managed processes may be spawned. Any component asking the supervisor to spawn a child during shutdown gets this error naming the process type. It prevents zombie children created while the supervisor is tearing down.

Solutions

  1. Check supervisor state before requesting a spawn and skip/queue the work during shutdown
  2. Retry the operation after the supervisor has restarted
  3. Fix race conditions where shutdown and new work are triggered concurrently
  4. Drain in-flight requests before calling stop()

Example fix

// before
supervisor.spawn('sdk-worker'); // may throw during shutdown
// after
try {
  supervisor.assertCanSpawn('sdk-worker');
  supervisor.spawn('sdk-worker');
} catch {
  queueAfterRestart('sdk-worker');
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (supervisor.isShuttingDown()) { deferWork(); } else { supervisor.spawn(type); }

Try / catch

try { supervisor.assertCanSpawn(type); supervisor.spawn(type); }
catch { pendingSpawns.push(type); supervisor.on('started', () => flushPendingSpawns()); }

Prevention

When it happens

Trigger: Requesting a spawn of process `type` after supervisor.stop() was called but before shutdown completed (stopPromise still pending or just non-null).

Common situations: A request or session arriving concurrently with a shutdown/restart; background tasks that lazily spawn workers racing a SIGTERM; tests that stop a shared supervisor then trigger more work.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17). Data as JSON: /api/errors/9ea2009d6401868f. Report an issue: GitHub.

Appendix: source

Thrown at src/supervisor/index.ts:135

      await this.stopPromise;
      return;
    }

    stopHealthChecker();
    this.stopPromise = runShutdownCascade({
      registry: this.registry,
      currentPid: process.pid
    }).finally(() => {
      this.started = false;
      this.stopPromise = null;
    });

    await this.stopPromise;
  }

  assertCanSpawn(type: string): void {
    if (this.stopPromise !== null) {
      throw new Error(`Supervisor is shutting down, refusing to spawn ${type}`);
    }
  }

  registerProcess(id: string, processInfo: ManagedProcessInfo, processRef?: Parameters<ProcessRegistry['register']>[2]): void {
    this.registry.register(id, processInfo, processRef);
  }

  unregisterProcess(id: string): void {
    this.registry.unregister(id);
  }

  getRegistry(): ProcessRegistry {
    return this.registry;
  }
}

const supervisorSingleton = new Supervisor(getProcessRegistry());

View on GitHub (pinned to d8bc9755e7)