Open
Conversation
When `argent mcp` runs as an orphaned process whose stderr pipe is broken (e.g. parent died), every `stderr.write` from the uncaughtException handler emits an async 'error' event. Without an 'error' listener that becomes another uncaughtException, runs the handler again, and so on forever. Move the handlers into `fatal-handlers.ts` and add three guards: - 'error' listeners on stdout/stderr exit cleanly when stdio is broken, before the failure becomes another uncaughtException - try/catch around `stderr.write` so a sync write failure exits instead of escaping - try/catch around the formatter so a throwing `.stack` getter or `toString` (the production trace pointed at defaultPrepareStackTrace) can't take down the handler Idempotent: a second `installFatalHandlers` call is a no-op.
`fatal-handlers.test.ts` imports the built dist/fatal-handlers.js so it exercises the same artifact that ships, but `npm test` would fail with ERR_MODULE_NOT_FOUND if the dispatcher hadn't been built first. CI is fine — it runs `tsc --build` at the workspace level — but local devs running `npm test` cold hit a confusing error. Add `pretest`/`pretest:watch` hooks that run `tsc` (incremental, non-destructive — unlike `build:dispatcher` which `rm -rf dist` would nuke any bundle outputs the dev had built).
Drop the pretest/pretest:watch hooks added in the previous commit. Instead of importing from dist/fatal-handlers.js (which required a prior build), the test now uses esbuild — already a devDependency — to transform src/fatal-handlers.ts into a tmp .mjs once in beforeAll, and spawned children import from there. `npm test` now works cold without touching dist/, no build dependency on the test, no script-hook artifacts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
One of our users reported occasional 100% CPU usage stale MCP server process.
I wasn't able to reproduce this bug directly in Codex. We only have non-codex repros that are able to consistantly reproduce a bug that looks like the one reported to us.
The bug in question is: Our error handler causes errors which throws it into an infinite loop.
More details:
When
argent mcpruns as an orphaned process whose stderr pipe is broken (e.g. parent died), everystderr.writefrom the uncaughtException handler emits an async 'error' event. Without an 'error' listener that becomes another uncaughtException, runs the handler again, and so on forever.Move the handlers into
fatal-handlers.tsand add three guards:stderr.writeso a sync write failure exits instead of escaping.stackgetter ortoString(the production trace pointed at defaultPrepareStackTrace) can't take down the handlerIdempotent: a second
installFatalHandlerscall is a no-op.