Skip to content

fix(core): bound multi-part tool outputs and evict older multimodal inlineData - #30180

Merged
DavidAPierce merged 4 commits into
google-gemini:mainfrom
tadipavan:b/29830-FATAL_ERROR
Nov 6, 2026
Merged

DavidAPierce merged 4 commits into
google-gemini:mainfrom
tadipavan:b/29830-FATAL_ERROR

Conversation

@tadipavan

Copy link
Copy Markdown
Contributor

Summary

Fixes a V8 Old Space heap out-of-memory crash (FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory) during long-running agentic sessions that repeatedly read multiple files (e.g., read_many_files) or inspect multimodal tool outputs (such as screenshots).

Details

  • Cumulative Multi-Part Array Truncation (packages/core/src/scheduler/tool-executor.ts):
    • Enforces a cumulative MAX_STORED_TOOL_OUTPUT_BYTES (64 KB) budget across array elements in ToolExecutor.truncateOutputIfNeeded and applies truncateFunctionResponsePart on the converted functionResponse parts in createSuccessResult and createCancelledResult. Previously, each element was checked against 64 KB independently before convertToFunctionResponse joined them into a single multi-megabyte string.
  • Multimodal inlineData Accounting & Eviction (packages/core/src/context/chatCompressionService.ts, packages/core/src/context/toolOutputMaskingService.ts):
    • Updates calculateHistoryByteSize and ToolOutputMaskingService to count nested functionResponse.parts inlineData bytes (used by Gemini 3 multimodal tool responses).
    • Strips nested functionResponse.parts when masking older tool responses in ToolOutputMaskingService so token savings are positive instead of negative (previously, retaining the 3,000-token inlineData inside maskedPart caused savings <= 0 and aborted masking).
    • Updates collapseOlderFunctionResponses to strip nested functionResponse.parts and sibling part.inlineData payloads outside RECENT_TURNS_PROTECTED (3), and bounds older uncollapsed exempt retrieval tool outputs (read_file, read_many_files, grep, etc.) to a 64 KB budget (MAX_EXEMPT_RETRIEVAL_HISTORY_BYTES).
  • Byte-Threshold Trigger & Turn ID Stability (packages/core/src/agents/local-executor.ts, packages/core/src/core/client.ts, packages/core/src/core/geminiChat.ts):
    • Triggers collapseOlderFunctionResponses in LocalAgentExecutor.tryCompressChat and GeminiClient.tryMaskToolOutputs when history exceeds COLLAPSE_HISTORY_BYTE_THRESHOLD (256 KB), even when estimated tokens are well below the 500,000-token compression threshold.
    • Preserves existing HistoryTurn.id values when updating chat history via setHistory in GeminiClient.tryMaskToolOutputs, and extracts BINARY_INJECTION_KEY before recording the initial tool response turn in GeminiChat.sendMessageStream.

Related Issues

Fixes #29830

How to Validate

  1. Build all packages:
    npm run build
  2. Run the regression and unit tests for the affected modules:
    npm test -w @google/gemini-cli-core -- src/agents/memory-leak-regression.test.ts src/context/chatCompressionService.test.ts src/context/toolOutputMaskingService.test.ts src/scheduler/tool-executor.test.ts
  3. Run workspace lint and typecheck:
    npm run lint && npm run typecheck

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

@tadipavan
tadipavan requested a review from a team as a code owner November 6, 2026 12:28
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical V8 heap out-of-memory crash occurring during long-running agentic sessions. By implementing stricter byte-level bounds on tool outputs, improving multimodal data accounting, and introducing proactive compression triggers based on memory usage rather than just token counts, the changes significantly improve the stability and memory footprint of the application.

Highlights

  • Memory Management: Enforced a cumulative 64 KB byte budget for multi-part tool outputs to prevent heap overflows during large file operations.
  • Multimodal Data Handling: Updated history size calculations and masking services to account for nested inlineData in Gemini 3 multimodal responses, ensuring proper eviction and masking.
  • Proactive Compression: Introduced a 256 KB history byte threshold to trigger chat compression even when token counts are low, preventing memory pressure.
  • Stability Improvements: Ensured stable HistoryTurn IDs during history updates and preserved binary injection keys to maintain context integrity.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@github-actions github-actions Bot added the size/l A large sized PR label Nov 6, 2026
@github-actions

github-actions Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

📊 PR Size: size/L

  • Lines changed: 601
  • Additions: +554
  • Deletions: -47
  • Files changed: 8

@tadipavan

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses heap out-of-memory issues and memory leaks by introducing history byte size thresholds to trigger collapsing of older function responses, optimizing the truncation of multi-part tool outputs, and adding comprehensive regression tests. Feedback on the changes highlights a critical bug in tool-executor.ts where multi-part tool outputs exceeding the byte budget are discarded instead of being written to the disk fallback, leading to data loss. Additionally, the history byte size calculation in chatCompressionService.ts should be updated to include nested text parts to prevent underestimating the history size.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces memory optimization mechanisms to prevent heap out-of-memory issues, including strict budget-based truncation of tool outputs and collapsing older function responses when history byte size thresholds are exceeded. The review feedback suggests a performance optimization in collapseOlderFunctionResponses to break out of the loop early once the exempt byte budget is exhausted, avoiding expensive size calculations on remaining older turns.

Note: Security Review did not run due to the size of the PR.

@gemini-cli gemini-cli Bot added the area/core Issues related to User Interface, OS Support, Core Functionality label Nov 6, 2026
@tadipavan

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses heap out-of-memory issues (GH-29830) by strictly bounding joined tool response outputs and collapsing older multimodal inlineData payloads when history byte size limits are exceeded. Key changes include introducing history byte size thresholds, updating history size calculations to account for nested parts, and refining the tool execution and masking services to enforce these limits. The feedback suggests enhancing robustness by defensively checking that nested parts are valid objects before accessing their properties in both the compression and masking services.

@tadipavan

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses heap out-of-memory issues (GH-29830) by introducing stricter history byte size thresholds and collapsing older function responses when under memory pressure. It updates history byte size calculations to account for nested multimodal data, bounds joined response outputs, and adds comprehensive regression tests. The review feedback suggests using object destructuring to dynamically exclude the parts property from functionResponse in chatCompressionService.ts rather than explicitly copying individual properties, which is fragile and prone to silent data loss.

@tadipavan

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses heap out-of-memory issues (GH-29830) by introducing stricter budgeting and truncation of history and tool outputs. Key changes include updating calculateHistoryByteSize to account for nested functionResponse.parts and inlineData, implementing a new history byte size threshold (COLLAPSE_HISTORY_BYTE_THRESHOLD) to trigger collapsing of older responses, and refactoring ToolExecutor to strictly budget and truncate multi-part array outputs. Additionally, comprehensive regression tests have been added to verify these memory-bounding behaviors. No review comments were provided, so I have no feedback to address.

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

Labels

area/core Issues related to User Interface, OS Support, Core Functionality size/l A large sized PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Crash]: FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory (V8 Heap Limit Exceeded at ~8.3GB)

2 participants