google-gemini / google-gemini/gemini-cli

bug: shell execution runs exit handling twice on spawn failure ('error' and 'close' both call handleExit)

Open Beginner friendly
#29,057 1 comment 0 reactions 0 assignees View on GitHub
area/agent status/need-triage
Dominant language
TypeScript
Stars
107k
Forks
14.6k
Avg merge
2d 3h
Merged PRs (30d)
45

Description

## What happened?

In the shell execution pipeline, both the child `'error'` and `'close'` events invoke `handleExit()`, and `handleExit` has no re-entrancy guard. Per Node's documented behavior, `'close'` fires after `'error'` when spawning fails — so every failed spawn runs exit handling **twice**: `onOutputEvent({ type: 'exit', ... })` fires twice, background-history finalization runs twice, and `cmdCleanup?.()` executes twice. If `'error'` fires mid-run on a successfully spawned child (e.g., kill/IPC failure), the result settles early on partial output before `'close'` arrives.

## Affected code

`packages/core/src/services/shellExecutionService.ts:819-838`:

```ts
child.on('error', (err) => {
error = err;
handleExit(1, null); // first settlement
});
// ...
child.on('close', (code, signal) => {
handleExit(code, signal); // second settlement for the same run
});
```

## How can this be reproduced?

Execute a command whose spawn fails (nonexistent executable / bad sandbox path). Observe two `exit` output events emitted for the single run (and doubled cleanup calls).

## What did you expect to happen?

Exactly one exit settlement per process run.

## Suggested direction

Add a `settled` flag inside `handleExit` (return immediately on second call), matching the pattern used elsewhere in this file for stream finalization.

---

*Found by source audit on current `main` (commit `5411f113c`); platform-independent. No open issue/PR covering this was found (searched: shell exit event twice).*

Contributor guide

Open the contributing guide

Research direction

Start in packages/core/src/services/shellExecutionService.ts:819-838 and inspect how the child 'error' and 'close' handlers call handleExit. Reproduce the issue with a command whose spawn fails, then verify that one process run emits one exit event and performs cleanup and background-history finalization once.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
cli
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
82/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.