google-gemini / google-gemini/gemini-cli
Temporary Directory Leak During Background Shell Execution
- Dominant language
- TypeScript
- Stars
- 107k
- Forks
- 14.6k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 45
Description
# Reliability: Temporary directory leak for background shell executions
**Category:** Reliability / Resource Leak
**Priority:** High
## Affected Components
- `packages/core/src/tools/shell.ts`
- `packages/core/src/services/ShellExecutionService.ts`
## Summary
When a shell command is executed with `is_background: true`, the CLI creates a temporary directory (`gemini-shell-*`) to store `bgpids.tmp`. This directory is never removed after the background task finishes, resulting in a permanent resource leak.
Over time, repeated background executions accumulate orphaned directories inside the system temporary folder.
## Current Behavior
The shell tool creates a temporary directory using `fs.mkdtempSync()` before executing the command.
For foreground commands, the directory is removed in the `finally` block.
For background commands, cleanup is intentionally skipped:
```ts
// Only clean up if NOT running in background.
if (!this.params.is_background) {
// cleanup...
}
```
However, ownership of this temporary directory is never transferred to `ShellExecutionService`, so nothing removes it after the background process exits.
## Expected Behavior
The temporary directory should be automatically deleted once the background process has completed.
## Steps to Reproduce
1. Run any background command (e.g., `sleep 10`) with `is_background: true`.
2. Inspect the system temp directory (`/tmp` or `%TEMP%`).
3. Observe a new `gemini-shell-*` directory.
4. Wait for the background process to finish.
5. The directory still exists.
## Impact
- Temporary directories accumulate indefinitely.
- Long-running CLI sessions or A2A server mode may create thousands of orphaned directories.
- Can eventually consume temporary storage or available inodes, leading to `ENOSPC` errors.
## Suggested Solution
Transfer ownership of the temporary directory to `ShellExecutionService`.
A minimal approach would be to:
- Extend `ShellExecutionService.background(...)` to accept the `tempDir` path.
- Store the directory alongside the background process metadata.
- Remove the directory when the background process exits using:
```ts
await fsPromises.rm(tempDir, {
recursive: true,
force: true,
});
```
This keeps the existing behavior unchanged while ensuring temporary resources are cleaned up after the background task completes.
## Testing
Add an integration test that:
1. Starts a short-lived background command.
2. Waits for it to exit.
3. Verifies the temporary directory has been deleted.
## Acceptance Criteria
- [ ] `ShellExecutionService` accepts ownership of the temporary directory.
- [ ] Temporary directory is deleted when the background process exits.
- [ ] Integration test verifies cleanup.
- [ ] No behavior change for foreground shell execution.
Contributor guide
Research direction
Start in packages/core/src/tools/shell.ts and packages/core/src/services/ShellExecutionService.ts, tracing how the temporary directory is created and how background process completion is handled. Pass ownership of the directory to the background execution path, then add an integration test that runs a short-lived background command and verifies the directory is deleted without changing foreground cleanup.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100