{"record":{"id":"d757c23e941c8e8f","repo":"thedotmack/claude-mem","slug":"worker-is-alive-but-readiness-timed-out-proceedi","errorCode":null,"errorMessage":"Worker is alive but readiness timed out — proceeding anyway","messagePattern":"Worker is alive but readiness timed out — proceeding anyway","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/services/worker-spawner.ts","lineNumber":127,"sourceCode":"      clearWorkerSpawnAttempted();\n      logger.info('SYSTEM', 'Worker became ready while waiting on live PID');\n      return 'ready';\n    }\n    const workerStillHealthy = await waitForHealth(port, 1000);\n    const workerPidStillAlive = cleanStalePidFile() === 'alive';\n    if (!workerStillHealthy && !workerPidStillAlive) {\n      logger.error('SYSTEM', 'Live PID disappeared before readiness endpoint became available');\n      return 'dead';\n    }\n    logger.warn('SYSTEM', 'Live PID detected but worker did not become ready before timeout');\n    return 'warming';\n  }\n\n  if (await waitForHealth(port, 1000)) {\n    clearWorkerSpawnAttempted();\n    const ready = await waitForReadiness(port, getPlatformTimeout(HOOK_TIMEOUTS.READINESS_WAIT));\n    if (!ready) {\n      logger.warn('SYSTEM', 'Worker is alive but readiness timed out — proceeding anyway');\n    }\n    logger.info('SYSTEM', 'Worker already running and healthy');\n    return ready ? 'ready' : 'warming';\n  }\n\n  const portInUse = await isPortInUse(port);\n  if (portInUse) {\n    logger.info('SYSTEM', 'Port in use, waiting for worker to become healthy');\n    const healthy = await waitForHealth(port, getPlatformTimeout(HOOK_TIMEOUTS.PORT_IN_USE_WAIT));\n    if (healthy) {\n      clearWorkerSpawnAttempted();\n      const ready = await waitForReadiness(port, getPlatformTimeout(HOOK_TIMEOUTS.READINESS_WAIT));\n      logger.info('SYSTEM', 'Worker is now healthy');\n      return ready ? 'ready' : 'warming';\n    }\n    // The port is bound but nothing answers health. Usually this is a dead\n    // worker whose surviving chroma sidecar chain (uvx -> uv -> python) holds\n    // the inherited listening socket — a ghost listener under a dead PID","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/worker-spawner.ts#L109-L145","documentation":"The worker is already running and passes the health check, but its readiness endpoint did not respond within READINESS_WAIT. The spawner treats this as non-fatal: it logs 'Worker already running and healthy' and returns 'warming' so callers can proceed or retry later.","triggerScenarios":"waitForHealth(port, 1000) succeeds (worker up) but waitForReadiness(port, getPlatformTimeout(READINESS_WAIT)) returns false — readiness endpoint slow, not yet implemented, or the worker is up but still loading models/session state.","commonSituations":"Version skew: older worker binary lacking the readiness route while health exists; heavy init (Chroma startup) delaying readiness; transient network/socket hiccup on localhost; very short platform timeout.","solutions":["Treat 'warming' as acceptable and retry the request shortly","Restart the worker so versions align (CLI restart / delete pid file)","Increase READINESS_WAIT timeout on slow machines","Confirm worker version matches the CLI to ensure the readiness route exists"],"exampleFix":"// before\nconst status = await ensureWorkerStarted(port);\nif (status !== 'ready') return;\n// after\nconst status = await ensureWorkerStarted(port);\nif (status === 'warming') return; // health OK; readiness will follow — proceed optimistically","handlingStrategy":"retry","validationCode":"const healthy = await waitForHealth(port, 1000);\nif (!healthy) throw new Error('worker not healthy at all'); // distinct from warming\nconst ready = await fetch(`http://localhost:${port}/readiness`).then(r => r.ok).catch(() => false);","typeGuard":null,"tryCatchPattern":"const status = await ensureWorkerStarted(port);\nif (status === 'warming') {\n  // health passed; poll readiness a bit longer before giving up\n  const ready = await waitForReadiness(port, 5000);\n}","preventionTips":["Keep CLI and worker versions in sync so the readiness route exists","Increase READINESS_WAIT on slow platforms","Poll readiness once more before declaring failure on 'warming'"],"tags":["worker","readiness","health-check","timeout"],"backgroundTag":"request-timeout","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"}