thedotmack/claude-mem · warning

Worker spawned but readiness endpoint not responding within…

Error message

Worker spawned but readiness endpoint not responding within window

What it means

After spawning a worker while holding the spawn lock, the readiness endpoint never responded within the window and the worker did not exit. The spawner logs this variant (vs the spawn-lock-holder variant) and returns 'warming' — the process may still come up later.

Solutions

  1. Poll health/readiness again after a short delay — 'warming' often resolves
  2. Inspect worker stdout/stderr logs for slow init or port mismatch
  3. Pre-warm the worker (start it before batch operations) to avoid cold-start latency
  4. If the process never becomes ready, kill it and let the next attempt respawn cleanly

Example fix

// before
if (status === 'warming') fail();
// after
if (status === 'warming') {
  const ready = await waitForReadiness(port, 10000); // extended poll
  if (ready) succeed();
}
Defensive patterns

Strategy: retry

Validate before calling

const up = await waitForHealth(port, 1000);
const ready = up ? await waitForReadiness(port, 15000) : false;
if (up && !ready) console.warn('worker warming; poll again');

Try / catch

const status = await ensureWorkerStarted(port);
if (status === 'warming') {
  await sleep(3000);
  const again = await ensureWorkerStarted(port); // second chance
}

Prevention

When it happens

Trigger: A gated spawn succeeded (process started) but waitForReadiness timed out and the worker was still alive (no 'Worker exited before readiness' boot failure logged), so the outcome is ambiguous: neither ready nor dead.

Common situations: Slow first boot (installing/starting Chroma, cold Bun/uv run); worker bound a different port than expected; readiness route slow because the worker is replaying session state; resource-starved CI machine.

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/9f3678ae83255d8b. Report an issue: GitHub.

Appendix: source

Thrown at src/services/worker-spawner.ts:218

      const workerPidStillAlive = cleanStalePidFile() === 'alive';
      const spawnedProcessStillAlive = spawnedPid !== undefined && spawnedPid > 0 && isPidAlive(spawnedPid);
      if (!workerStillHealthy && !workerPidStillAlive && !spawnedProcessStillAlive) {
        if (!spawnLockHeld) {
          logger.error('SYSTEM', 'Spawn-lock holder never produced a live worker before readiness timed out');
          return 'dead';
        }
        // We launched it and it is gone, so the bundle itself is the suspect —
        // and its stderr went to a hidden window. Ask it again where we can
        // hear the answer.
        lastWorkerBootFailure = probeWorkerBootFailure(workerScriptPath);
        logger.error(
          'SYSTEM',
          'Worker exited before readiness endpoint became available',
          lastWorkerBootFailure ? { bootFailure: lastWorkerBootFailure } : {}
        );
        return 'dead';
      }
      logger.warn('SYSTEM', spawnLockHeld
        ? 'Worker spawned but readiness endpoint not responding within window'
        : 'Spawn-lock holder\'s worker not ready within window');
      return 'warming';
    }
    clearWorkerSpawnAttempted();
    // touchPidFile is existsSync-guarded and merely refreshes the live worker's
    // pid-file mtime — correct for lock losers too, since the worker IS up.
    touchPidFile();
    logger.info('SYSTEM', spawnLockHeld
      ? 'Worker started successfully'
      : 'Worker is up (started by another launcher)');
    return 'ready';
  } finally {
    if (spawnLockHeld) releaseSpawnLock();
  }
}

View on GitHub (pinned to d8bc9755e7)