Skip to content

panda mcp: process spins at ~100% CPU indefinitely after uncaught exception #3553

@cloud-walker

Description

@cloud-walker

Version

@pandacss/mcp@1.11.1
Platform: macOS 26.5 (Darwin arm64), Node.js 24.12.0

Description

When panda mcp is launched as a Claude Code MCP server, the process eventually hits an uncaught exception and enters a tight infinite CPU-spinning loop. It never exits and must be killed manually. The process also persists as an orphan after the parent Claude Code session ends (parent becomes PID 1), continuing to burn ~100% CPU until manually killed.

We had 4 simultaneous instances pegged at ~100% CPU each across different worktrees — the oldest had been running for 1h 22min, consuming 79 minutes of CPU time.

Call stack (from macOS sample)

uv__run_check → CheckImmediate → TriggerUncaughtException
  → InspectorConsoleCall  (console.log/error inside the error handler)
  → v8::Function::Call → Invoke → TriggerUncaughtException
  → InspectorConsoleCall → ...  (tight infinite loop)

The error handler calls console.log/console.error, which triggers further JS execution that re-throws, recursively looping forever. The Node.js event loop never blocks — it spins uv__run_check continuously at 100% CPU.

Steps to reproduce

  1. Configure panda mcp as a Claude Code MCP server via .mcp.json:
    { "mcpServers": { "panda": { "command": "npx", "args": ["panda", "mcp"] } } }
  2. Open a Claude Code session in a workspace using that config.
  3. After some time (or on any unhandled error inside the MCP server), panda mcp pegs at 100% CPU.
  4. Close the Claude Code session — the process is not killed, it becomes orphaned and keeps spinning.

Expected behavior

The MCP server should catch unhandled exceptions, log them, and exit with a non-zero code rather than looping infinitely.

Suggested fix

Add a top-level uncaught exception guard in the MCP server entry point:

process.on('uncaughtException', (err) => {
  console.error('[panda mcp] uncaught exception, exiting:', err)
  process.exit(1)
})

process.on('unhandledRejection', (reason) => {
  console.error('[panda mcp] unhandled rejection, exiting:', reason)
  process.exit(1)
})

This prevents the recursive re-entry into the error handler that causes the spin loop, and ensures the process exits cleanly so the MCP host can restart it if needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions