Skip to content

[hermes-plugin] provider.py replaces a client whose reader thread died without stop() — the still-running node child (model loaded) is orphaned, an exited one is never wait()ed #105

Description

@devinmlowe

Evidence

interfaces/hermes-plugin/mcp_client.py:51-58:

@property
def alive(self) -> bool:
    # A child whose stdout reader has ended (EOF or reader crash) can
    # never answer again, so it counts as dead even if the PID lingers
    return (self._proc is not None and self._proc.poll() is None and not self._reader_dead)

interfaces/hermes-plugin/provider.py:305-312:

if self._client is None or not self._client.alive:
    client = McpStdioClient(self._server_command(), env=self._child_env(), cwd=...)
    client.start()
    self._client = client          # old client dropped, stop() never called

stop() (mcp_client.py:109-…) is the only path that closes stdin, waits, and kills the process group.

Why it's a bug

When only the reader thread died (_reader_dead true, poll() is None), the old node dist/interfaces/mcp/server.js keeps running with its embedding model and database connection open, and nothing ever signals it; each recurrence adds another ~300 MB process. When the process did exit, it is never wait()ed until CPython's GC finalises the Popen, holding pipe FDs meanwhile. Trigger is a reader-thread exception (malformed frame, decode error) on the stdio transport — rare, so P3.

Suggested direction

Capture the old client and call old.stop() (best-effort, short grace) before assigning the replacement; stop() already tolerates an exited process.

Related: #41, #17.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority: P3Later: consistency, hardening, design work with no observed failures

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions