Skip to content

Exit instead of spinning when orphaned or fatally errored - #36

Merged
CakeRepository merged 1 commit into
CakeRepository:masterfrom
S0ya13:fix/orphan-spin-exit-on-fatal
Oct 19, 2026
Merged

CakeRepository merged 1 commit into
CakeRepository:masterfrom
S0ya13:fix/orphan-spin-exit-on-fatal

Conversation

@S0ya13

@S0ya13 S0ya13 commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Fixes #35.

Problem

The uncaughtException/unhandledRejection handlers in src/index.ts logged the error and continued running. When stdio is broken (orphaned process after the parent exits, EPIPE on every write), each logging attempt throws again, so the process enters a permanent throw→log→throw cycle at ~100% CPU instead of exiting.

Observed in production on macOS/arm64: 6–10 orphaned node ... 1password-mcp processes (PPID 1) at ~70–100% CPU each, ~800% CPU total, load average 88, battery drain + overheating. Sampling one orphan showed ~1291/1292 samples in uv__run_check → CheckImmediate → InternalMakeCallback → TriggerUncaughtException → FormatStackTrace — a per-tick exception loop through the log path.

I reproduced the mechanism with equivalent log-and-continue handlers + broken stderr: permanent 98.8% CPU spin, PPID 1 — same signature.

Fix (src/index.ts)

  • Fatal errors (uncaughtException/unhandledRejection) are logged once via a guarded reporter (logging itself can't throw out, stderr may be a broken pipe) and then process.exit(1) — a supervisor can restart cleanly.
  • stdin end/close → process.exit(0): nobody left on the other end means this server is an orphan; exit instead of idling/spinning.
  • SIGTERM/SIGINT → clean process.exit(0), guarded against re-entry.

Verification

  • Before: server kept running after a fatal error (confirmed against pre-fix build); after: logs Uncaught exception. once and exits non-zero; stdin EOF → exits 0.
  • New regression tests tests/stdio-lifecycle.test.ts (fail on old code: 1 failed / 1 passed; pass on new code: 2 passed).
  • Full suite: 12 files, 417 tests passed; npm run lint clean.

@CakeRepository
CakeRepository merged commit 3abbc34 into CakeRepository:master Oct 19, 2026
CakeRepository pushed a commit that referenced this pull request Oct 19, 2026
Bump version in package.json, package-lock.json, server.json and
SERVER_VERSION, and cut the 5.1.0 CHANGELOG entry covering the stdio
lifecycle fix for orphaned/crashed servers spinning at 100% CPU (#36,
fixes #35) and the @modelcontextprotocol/client 2.2.0 dev dependency
update (#34).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuaDwBdUFraDUa7S9kfo3G
CakeRepository added a commit that referenced this pull request Oct 19, 2026
Bump version in package.json, package-lock.json, server.json and
SERVER_VERSION, and cut the 5.1.0 CHANGELOG entry covering the stdio
lifecycle fix for orphaned/crashed servers spinning at 100% CPU (#36,
fixes #35) and the @modelcontextprotocol/client 2.2.0 dev dependency
update (#34).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DuaDwBdUFraDUa7S9kfo3G
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Orphaned server spins at ~100% CPU in uncaught-exception loop instead of exiting

2 participants