thedotmack/claude-mem · warning

Worker service did not confirm shutdown; continuing…

Error message

Worker service did not confirm shutdown; continuing uninstall cleanup.

What it means

During uninstall, claude-mem asks the background worker to shut down via shutdownWorkerAndWait and only proceeds to clean up settings once the worker has confirmed it stopped (health probe returns ECONNREFUSED). This warning is emitted when a worker was detected as running but never confirmed shutdown within the 10s budget, meaning an in-memory worker may still be alive while the uninstaller continues removing files/settings. It exists because the installer deliberately fails closed rather than corrupting state under a live worker.

Solutions

  1. Check if a claude-mem worker is still listening on CLAUDE_MEM_WORKER_PORT (curl http://127.0.0.1:<port>/api/health) and kill it manually, then re-run uninstall
  2. Restart the machine or kill stale bun/worker processes to release the port
  3. Increase the shutdown timeout and retry uninstall after fixing whatever is blocking the worker
  4. Re-run the uninstall after the worker has exited; settings cleanup will then proceed safely

Example fix

// before: uninstall proceeds with live worker
const result = await shutdownWorkerAndWait(workerPort, 10000);
// after: fail fast and instruct the user
const result = await shutdownWorkerAndWait(workerPort, 10000);
if (result.workerWasRunning && !result.stopped) {
  p.log.error(`Worker on port ${workerPort} did not stop. Kill it and re-run uninstall.`);
  process.exit(1);
}
Defensive patterns

Strategy: retry

Validate before calling

const res = await fetch(`http://127.0.0.1:${port}/api/health`, { signal: AbortSignal.timeout(1000) });
const workerLive = res.ok; // if true, ensure shutdown completes before uninstall

Type guard

function shutdownConfirmed(r: { workerWasRunning: boolean; stopped: boolean }): boolean {
  return !r.workerWasRunning || r.stopped;
}

Try / catch

const result = await shutdownWorkerAndWait(port, 10000);
if (result.workerWasRunning && !result.stopped) {
  console.warn('Worker still live; aborting uninstall to avoid corrupting settings.');
  return;
}

Prevention

When it happens

Trigger: Worker POST /api/admin/shutdown times out or returns non-OK; the health probe after shutdown returns anything other than a connection refused (reset, timeout, protocol error) within the 10s window.

Common situations: Worker process hung or deadlocked; worker busy on a long task; port occupied by another process that answers health checks; slow machine where 10s teardown is insufficient.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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

Appendix: source

Thrown at src/npx-cli/commands/uninstall.ts:277

  } else if (process.stdin.isTTY) {
    const shouldContinue = await p.confirm({
      message: 'Are you sure you want to uninstall claude-mem?',
      initialValue: false,
    });

    if (p.isCancel(shouldContinue) || !shouldContinue) {
      p.cancel('Uninstall cancelled.');
      return;
    }
  }

  const workerPort = SettingsDefaultsManager.get('CLAUDE_MEM_WORKER_PORT');
  try {
    const result = await shutdownWorkerAndWait(workerPort, 10000);
    if (result.workerWasRunning && result.stopped) {
      p.log.info('Worker service stopped.');
    } else if (result.workerWasRunning) {
      p.log.warn('Worker service did not confirm shutdown; continuing uninstall cleanup.');
    }
  } catch (error: unknown) {
    console.warn('[uninstall] Worker shutdown attempt failed:', error instanceof Error ? error.message : String(error));
  }

  // #2568 — server-runtime teardown. Gated on the installed/selected runtime so
  // the worker uninstall path is completely unchanged. The bundled Docker
  // compose stack lives under the marketplace dir; if it's present we treat the
  // stack as locally managed and instruct teardown (the actual `docker compose
  // down -v` is an operator/CI side effect, not run from this Node process).
  const selectedRuntime = readSelectedRuntime();
  if (selectedRuntime === 'server') {
    if (existsSync(join(marketplaceDirectory(), 'docker-compose.yml'))) {
      p.log.info(
        'Server runtime detected. Tear down the bundled stack with '
          + '`docker compose down -v --remove-orphans` (stops + removes pg + redis/valkey).',
      );
    } else {

View on GitHub (pinned to d8bc9755e7)