Skip to content

[Windows] Plugin update orphans the worker port (ghost LISTENING socket), blocking all Claude Code prompts with no graceful recovery #2899

Description

@susan-jse

Summary

After updating claude-mem, every UserPromptSubmit in Claude Code was blocked with:

UserPromptSubmit operation blocked by hook: [... worker-service.cjs hook claude-code session-init]:
claude-mem worker unreachable for 13 consecutive hooks.

The root cause turned out to be that the old worker died during the update but left an orphaned LISTENING socket on the worker port (37777). The new worker could not bind to the port and died on startup, while the dead PID still appeared to "own" the port — so no clean respawn ever happened, and every hook blocked Claude Code entirely. Restarting VS Code did not help, because the worker daemon is a separate process from the editor.

This is the Windows manifestation of the "zombie worker / no self-recovery" problem already described in #2292, combined with the "hooks hard-block the whole session" problem in #729.

Environment

  • OS: Windows (PowerShell; system messages localized)
  • Client: VS Code (Claude Code)
  • Node.js: v24.5.0
  • Worker runtime: bun (bundled)
  • claude-mem version: v13.5.0 update to v13.5.6

Steps to reproduce

  1. Have claude-mem installed and its worker running.
  2. Update the claude-mem plugin while the worker is still running.
  3. Start a new Claude Code session in VS Code.
  4. Every prompt is blocked with claude-mem worker unreachable for N consecutive hooks.
  5. Restarting VS Code does not fix it.

Diagnosis (what I observed)

Command Result
worker-cli.js restart Failed to restart: Process died during startup
netstat -ano | findstr 37777 PID 11160 still shown LISTENING on 127.0.0.1:37777
taskkill /PID 11160 /F "process not found" — the owning process was already dead
taskkill /IM bun.exe /F "process not found" — no bun process was actually running
curl http://127.0.0.1:37777/api/health connection refused (nothing responds)

Conclusion: the port shows as LISTENING under a PID that no longer exists — an orphaned socket the OS had not released. Because the port looks occupied, the freshly spawned worker fails to bind and dies during startup; because a (dead) PID still appears to own it, the spawner never performs a clean respawn. The hook then blocks every Claude Code prompt instead of degrading gracefully.

Workaround that fixed it

Move the worker to a free port so it sidesteps the stuck socket entirely:

  1. Edit ~/.claude-mem/settings.json and change the worker port:
   "CLAUDE_MEM_WORKER_PORT": 37790
  1. Remove any stale PID file: del "$HOME\.claude-mem\worker.pid"
  2. Start the worker:
   node "$HOME\.claude\plugins\marketplaces\thedotmack\plugin\scripts\worker-cli.js" start

Worker started (PID: ...)
4. Verify on the new port: curl http://127.0.0.1:37790/api/health → healthy JSON.

(A full reboot also clears the orphaned socket, but that is heavy-handed for a plugin update.)

Expected behavior

  1. Clean handoff on update: updating the plugin should stop the old worker before swapping binaries, so it cannot orphan its port.
  2. Non-blocking hooks: memory is a supplementary feature. If the worker is unreachable, the session should continue without memory (log a warning) rather than blocking every prompt. (Same request as Worker startup blocks Claude Code entirely when not ready within 15 seconds #729.)
  3. Self-recovery for a stuck port: the spawner should detect "port appears held but unresponsive / owning PID is dead" and recover automatically — kill the stale entry and rebind, or fall back to a free port — instead of dying on startup. (Related: Hooks silently block every Claude Code event with No stderr output once recordWorkerUnreachable threshold trips #2292, Bug B.)

Related issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugConfirmed bug

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions