[Jamie] Cap accumulated stdout in bash exec to prevent RangeError crash - #1645
Merged
Conversation
## Problem `mcp/src/repo/bash.ts` accumulates child-process stdout into a single JS string with no size cap (`stdout += data.toString();`). When a command produces enough output, the string exceeds V8's maximum string length and Node throws `RangeError: Invalid string length` inside the stream `data` event. Because that throw happens outside the Promise executor, it is uncaught and crashes the whole MCP server (repo2graph), forcing a restart. Observed in production: ``` file:///usr/src/app/build/repo/bash.js:90 stdout += data.toString(); RangeError: Invalid string length ``` ## Fix Re-enable and repair the (currently commented-out) truncation guard in both `execShellCommand` and the sibling `execRipgrepCommandDirect`, but with a **large, safe byte cap** (~8 MB) instead of the old 10,000-char cap, so normal large outputs are not truncated — only pathological output that would otherwise crash the process. When the cap is exceeded, kill the process, clear the timeout, and resolve with the truncated output plus a clear marker, rather than throwing. The old 10,000-char cap is intentionally NOT restored — it was far too small and would truncate legitimate results. The goal is only to stay safely under V8's string-length limit.
gonzaloaune
requested review from
Evanfeenstra and
fayekelmith
as code owners
September 4, 2026 12:44
Evanfeenstra
added a commit
that referenced
this pull request
Sep 4, 2026
The agent step's `bash` truncated stdout at 10,000 chars, which is far too small for legitimate retrieval — a lockfile, a full test log, a large JSON response. It was also inconsistent with the agent's own file-read path: `view` allows 200,000 chars, so `cat foo.json` truncated where `view foo.json` did not. Match them (BASH_MAX_CHARS = FILE_VIEW_MAX_CHARS). This stays a context-budget cap rather than going to a crash-guard-sized ceiling like #1645's 8 MB: the agent loop keeps every tool result in the message history for the whole run, so bash output has to stay well under the model's context window. Separately, `capture()` accumulated stderr with no cap at all — the same RangeError class #1645 fixed for stdout, reachable through the agent's 10-minute bash (a noisy build), and an uncapped stderr also went straight into the model's context via the rejection message. Cap it on accumulation and in the error string. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.
Problem
mcp/src/repo/bash.tsaccumulates child-process stdout into a single JS string with no size cap (stdout += data.toString();). When a command produces enough output, the string exceeds V8's maximum string length and Node throwsRangeError: Invalid string lengthinside the streamdataevent. Because that throw happens outside the Promise executor, it is uncaught and crashes the whole MCP server (repo2graph), forcing a restart.Observed in production:
Fix
Re-enable and repair the (currently commented-out) truncation guard in both
execShellCommandand the siblingexecRipgrepCommandDirect, but with a large, safe byte cap (~8 MB) instead of the old 10,000-char cap, so normal large outputs are not truncated — only pathological output that would otherwise crash the process. When the cap is exceeded, kill the process, clear the timeout, and resolve with the truncated output plus a clear marker, rather than throwing.The old 10,000-char cap is intentionally NOT restored — it was far too small and would truncate legitimate results. The goal is only to stay safely under V8's string-length limit.