Skip to content

consult: gemini crashes on large PR diffs (V8 heap exhaustion) #680

@waleedkadous

Description

@waleedkadous

Summary

consult gemini branch crashes on PRs with diffs >500KB. V8 heap exhaustion in the spawned gemini-cli subprocess truncates stdout mid-stream, causing JSON.parse to fail. Codex and Claude are unaffected because they use in-process SDKs.

Reported by the shannon-workspace architect after losing gemini signal on multiple critical PR reviews (shannon PRs #642, #650, #568 phases 5-7, #629 Phase B). CMAP degraded to 2-way exactly when 3-way was most needed.

Symptoms

4/4 failure rate on large PRs, two failure modes:

  • (a) Failed to extract usage: Unexpected end of JSON input + exit 1 after ~20s. V8 heap stack traces: AfterScanDir, uv__async_io, ArrayUnshift
  • (b) exit 13 after 0.4s (same fragile JSON path, known gemini-cli issue)

Root Cause

gemini-cli v0.37.1 runs out of V8 old-space (~1.7 GB default) in the subprocess consult spawns. Contributing factors:

  1. gemini-cli eagerly runs loadServerHierarchicalMemory / JIT-context directory walk (graceful-fs wrapping fs.readdir — produces the ArrayUnshift + AfterScanDir frames)
  2. Large prompt passed as argv
  3. advanced.autoConfigureMemory is available in gemini-cli for this case but defaults OFF

Only gemini is affected because only gemini is shelled out and only gemini parses JSON from a buffered child stdout. Codex and Claude run in-process within consult's own Node process.

Code Location

packages/codev/src/commands/consult/index.ts:

  • Line 622: prompt passed as argv: cmd = [config.cli, '--output-format', 'json', ...config.args, query];
  • Line 652: spawn(cmd[0], cmd.slice(1), { cwd, env, stdio: ['ignore', 'pipe', 'inherit'] })
  • No NODE_OPTIONS set on spawn env

Proposed Fix

Ideally both:

Option A — bump heap via NODE_OPTIONS (survives gemini's internal relaunch):

env.NODE_OPTIONS = [process.env.NODE_OPTIONS ?? '', '--max-old-space-size=8192'].join(' ').trim()

Option B — pipe prompt via stdin instead of argv:
Change spawn stdio to ['pipe', 'pipe', 'inherit'], write query to child.stdin. gemini's non-interactive readStdin() path accepts this. Avoids ARG_MAX and keeps V8 from holding the prompt twice.

User-Side Workaround

Until a fix ships, users can set in ~/.gemini/settings.json:

{ "advanced": { "autoConfigureMemory": true } }

Related Upstream Issues

google-gemini/gemini-cli: #1740, #2993, #11321, #16271 (tracking), #22789

Impact

When CMAP is asked to review the largest, riskiest PRs (exactly when 3-way signal matters most), gemini fails silently and the user loses a full third of the consultation value.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions