google-gemini / google-gemini/gemini-cli

bug: extension update rollback copies an empty temp dir - restores nothing after a failed update

Open
#29,033 5 comments 0 reactions 0 assignees View on GitHub
area/platform effort/small kind/bug priority/p2 status/bot-triaged status/need-information
Dominant language
TypeScript
Stars
107k
Forks
14.6k
Avg merge
2d 3h
Merged PRs (30d)
45

Description

## What happened?

When an extension update fails, `update.ts` claims to roll back by copying a temp directory over the live extension directory — but that temp directory is created **empty** and nothing is ever written into it. The "rollback" copies zero files; its only observable effect is making the tree writable. Worse, `installOrUpdateExtension` may have already **deleted the old extension directory** before failing, so the extension ends up half-installed/destroyed while the logs claim a rollback happened.

## Affected code

`packages/cli/src/config/extensions/update.ts:102`:

```ts
const tempDir = await ExtensionStorage.createTmpDir(); // created EMPTY
```

`packages/cli/src/config/extensions/update.ts:137-149`:

```ts
} catch (e) {
debugLogger.error(`Error updating extension, rolling back. ${getErrorMessage(e)}`);
dispatchExtensionStateUpdate({ ... ERROR ... });
await copyExtension(tempDir, extension.path); // copies an empty dir
throw e;
} finally {
await fs.promises.rm(tempDir, { recursive: true, force: true });
}
```

`copyExtension` is `fs.promises.cp(source, destination, { recursive: true })` (`extension-manager.ts:1266-1272`). The new version is downloaded into a *different* temp dir inside `installOrUpdateExtension`; this one is never populated.

## How can this be reproduced?

1. Install any extension from GitHub.
2. Force an update failure after uninstall of the previous version (e.g., point at a release asset that 404s mid-flow).
3. Inspect the extension directory: old version gone, no restoration, log says "rolling back".

## What did you expect to happen?

A failed update leaves the previously working version in place.

## Impact

Data loss for the extension: a network blip during `gemini extensions update` can leave it broken until manual reinstall.

## Suggested direction

Snapshot the current extension dir into `tempDir` **before** mutating anything (copy, not move), and restore from it on failure — or make `installOrUpdateExtension` perform its swap atomically (staging dir + rename).

---

*Found by source audit on current `main` (commit `5411f113c`); platform-independent. Related but distinct: #27200/#19013 address transient cleanup failures, not this no-op rollback.*

Contributor guide

Open the contributing guide

Research direction

Start in packages/cli/src/config/extensions/update.ts around lines 102 and 137-149, then trace installOrUpdateExtension and copyExtension in extension-manager.ts:1266-1272. Verify how the current extension is changed or removed before the update fails. Done means a failed update restores the previously working extension instead of copying an empty directory, while the temporary snapshot is cleaned up.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.