thedotmack/claude-mem · warning

Worker is ready but still reports a stale version; not recyc

Error message

Worker is ready but still reports a stale version; not recycling again in this hook invocation (one recycle per hook event)

What it means

Amplifier guard: a hook recycles a version-mismatched worker at most once per invocation. After readiness, warnIfVersionStillMismatched re-fetches the worker's health version; if it still differs from the plugin's version, this warning fires and the hook returns success anyway — recycling again in the same invocation would re-create a restart storm. The NEXT hook event retries the recycle.

Source

Thrown at src/shared/worker-utils.ts:429

      await workerHttpRequest('/api/health', { timeoutMs: HEALTH_CHECK_TIMEOUT_MS });
    } catch {
      return true;
    }
    if (Date.now() - start >= timeoutMs) return false;
    await new Promise<void>(resolve => setTimeout(resolve, 200));
  }
}

/**
 * Amplifier guard: a hook recycles a stale worker AT MOST once per
 * invocation. If the worker that became ready still reports a mismatched
 * version, warn and return — the NEXT hook event retries. Recycling again in
 * the same invocation re-creates the restart storm.
 */
async function warnIfVersionStillMismatched(expectedPluginVersion: string): Promise<void> {
  const observedVersion = await fetchWorkerHealthVersion();
  if (observedVersion !== null && observedVersion !== expectedPluginVersion) {
    logger.warn('SYSTEM', 'Worker is ready but still reports a stale version; not recycling again in this hook invocation (one recycle per hook event)', {
      pluginVersion: expectedPluginVersion,
      workerVersion: observedVersion,
    });
  }
}

async function isWorkerPortAlive(): Promise<boolean> {
  let healthy: boolean;
  try {
    healthy = await isWorkerHealthy();
  } catch (error: unknown) {
    logger.debug('SYSTEM', 'Worker health check threw', {
      error: error instanceof Error ? error.message : String(error),
    });
    return false;
  }
  if (!healthy) return false;

View on GitHub (pinned to 8bc631a71a)

Solutions

  1. Trigger one more hook event (open a new Claude session) — the next invocation retries the recycle; often self-heals.
  2. If it persists, use the logged pluginVersion vs workerVersion to locate duplicate installs and remove the stale one.
  3. Run npm run build-and-sync to rebuild and re-sync the plugin so resolved script and version agree.
  4. As a last resort, kill the worker manually so the next hook spawns a fresh one from the resolved script.
Defensive patterns

Strategy: retry

Validate before calling

const observed = await fetchWorkerHealthVersion();
if (observed !== null && observed !== expectedPluginVersion) {
  // defer to next hook event — do NOT recycle again now
  return;
}

Type guard

const isVersionMismatch = (observed: string | null, expected: string): boolean =>
  observed !== null && observed !== expected;

Prevention

When it happens

Trigger: A stale worker was killed and respawned, but the worker that came up still reports a version different from expectedPluginVersion — e.g. resolution picked an old worker-service build, or version constants drifted between plugin and worker.

Common situations: Upgrade left two copies of the plugin/worker scripts on disk; symlinked marketplace install lagging the built one; partial build-and-sync.

Related errors


AI-assisted analysis of thedotmack/claude-mem@8bc631a71a (2026-08-20). Data as JSON: /api/errors/10460978b1c8d1b9. Report an issue: GitHub.