Skip to content

fix(hooks): prevent SessionEnd from firing twice in non-interactive mode - #22139

Merged
Adib234 merged 4 commits into
google-gemini:mainfrom
krishdef7:fix/session-end-double-fire-18019
Mar 27, 2026
Merged

Adib234 merged 4 commits into
google-gemini:mainfrom
krishdef7:fix/session-end-double-fire-18019

Conversation

@krishdef7

@krishdef7 krishdef7 commented Mar 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Removes a duplicate SessionEnd hook registration in gemini.tsx that caused the hook to fire twice when exiting non-interactive mode.

Details

main() registered a SessionEnd cleanup in the shared initialization block, which runs for both interactive and non-interactive modes. The non-interactive path then registered an identical second cleanup, causing fireSessionEndEvent to fire twice on exit.

Interactive mode was unaffected, it calls startInteractiveUI() and returns before reaching the duplicate registration.

Related Issues

Fixes #18019

How to Validate

Configure a SessionEnd hook command and run gemini in non-interactive mode (e.g. echo "hello" | gemini). Verify the hook fires exactly once on exit.

Run unit tests: npx vitest run packages/cli/src/gemini_cleanup.test.tsx

Pre-Merge Checklist

  • Added/updated tests (if needed)
  • Noted breaking changes (none)

@krishdef7
krishdef7 requested a review from a team as a code owner March 12, 2026 09:12
@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 bug where the SessionEnd hook was inadvertently triggered twice during the termination of non-interactive sessions. By removing a duplicate registration, the change ensures that session cleanup processes are executed precisely once, leading to more predictable and correct application behavior, particularly in automated or script-driven environments.

Highlights

  • SessionEnd Hook Fix: Eliminated a redundant SessionEnd hook registration in gemini.tsx to prevent it from firing twice when the application exits in non-interactive mode.
Changelog
  • packages/cli/src/gemini.tsx
    • Removed a duplicate SessionEnd hook registration that was causing the hook to fire twice in non-interactive mode.
Activity
  • The author has completed the pre-merge checklist, including confirming that tests were added/updated as needed.
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 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 counter productive. 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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

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. ↩

@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 a bug where the SessionEnd hook was firing twice in non-interactive mode. The cause was a duplicate registration of the cleanup hook in the non-interactive code path, while a general registration already existed for both modes. The change correctly removes this redundant registration. The fix is straightforward and effectively resolves the issue. I have no further comments or suggestions.

@gemini-cli gemini-cli Bot added priority/p1 Important and should be addressed in the near term. area/core Issues related to User Interface, OS Support, Core Functionality help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! labels Mar 12, 2026
@VibhorGautam

Copy link
Copy Markdown

/assign

@Adib234 Adib234 self-assigned this Mar 13, 2026
@Adib234

Adib234 commented Mar 13, 2026

Copy link
Copy Markdown
Contributor

Hi, thank you for this PR can you add tests please

@krishdef7
krishdef7 force-pushed the fix/session-end-double-fire-18019 branch from 421e394 to f4ca4d0 Compare March 13, 2026 15:17
@krishdef7

Copy link
Copy Markdown
Contributor Author

@Adib234 Added a unit test in gemini_cleanup.test.tsx that verifies registerCleanup is called exactly once for SessionEnd in non-interactive mode. Also rebased onto upstream/main so the branch is clean. Let me know if anything else is needed.

@krishdef7
krishdef7 force-pushed the fix/session-end-double-fire-18019 branch 4 times, most recently from 6c8b74d to e348c38 Compare March 16, 2026 14:51
Comment thread packages/cli/src/gemini_cleanup.test.tsx Outdated
Comment thread packages/cli/src/gemini_cleanup.test.tsx Outdated
@krishdef7

Copy link
Copy Markdown
Contributor Author

@Adib234 All review comments addressed in the latest commits. Tests pass locally (1 passed | 1 skipped). Ready for re-review when you have a moment.

@Adib234
Adib234 enabled auto-merge March 18, 2026 14:05
auto-merge was automatically disabled March 20, 2026 18:14

Head branch was pushed to by a user without write access

@krishdef7
krishdef7 force-pushed the fix/session-end-double-fire-18019 branch from 0032c54 to f142f00 Compare March 20, 2026 18:14
@krishdef7

Copy link
Copy Markdown
Contributor Author

@Adib234, rebased onto main, branch is clean (3 commits, 0 behind upstream). Could you re-enable auto-merge and help get a code owner to approve CI workflows? The bot and all checks are good, just needs maintainer sign-off.

@Adib234

Adib234 commented Mar 23, 2026

Copy link
Copy Markdown
Contributor

Can you show logs that show that SessionEnd is not fired twice in non-interactive mode?

…ode (google-gemini#18019)

The shared initialization block in main() registered a SessionEnd
cleanup at line 616 for all modes. The non-interactive path then
registered a second identical cleanup at line 798, causing
fireSessionEndEvent to fire twice on exit.

Interactive mode was unaffected (it returns before reaching line 798).

Fix: remove the duplicate registration in the non-interactive path.
The shared registration at line 616 already covers both modes.

Fixes google-gemini#18019
@krishdef7
krishdef7 force-pushed the fix/session-end-double-fire-18019 branch from f142f00 to 13685f7 Compare March 24, 2026 15:38
@krishdef7

krishdef7 commented Mar 24, 2026 •

Copy link
Copy Markdown
Contributor Author

@Adib234, Both items addressed.

1. TypeScript fix pushed

Added type HookSystem to imports and as unknown as HookSystem cast to mockHookSystem, the partial mock object wasn't satisfying the full HookSystem interface, causing the type error across all CI platforms (Linux, macOS, Windows). Branch is rebased onto current main.

2. Proof that SessionEnd fires exactly once

The unit test directly asserts this at the code level:

expect(mockHookSystem.fireSessionEndEvent).toHaveBeenCalledTimes(1);
expect(mockHookSystem.fireSessionEndEvent).toHaveBeenCalledWith(SessionEndReason.Exit);

How it works: mocks registerCleanup to capture all registered callbacks, runs every one of them, then asserts fireSessionEndEvent was called exactly once, directly catching any duplicate registration. This is a stronger guarantee than a runtime log because it exercises the exact fixed code path in gemini.tsx and would fail immediately if the duplicate were reintroduced.

Local run confirming it passes:

![vitest output showing ✓ should register SessionEnd hook exactly once in non-interactive mode 13ms]
Screenshot 2026-03-24 212206

Could you re-enable auto-merge and approve the 3 pending CI workflows?

@Adib234
Adib234 enabled auto-merge March 24, 2026 19:09
@krishdef7

Copy link
Copy Markdown
Contributor Author

@Adib234 The E2E failure is macOS-specific, E2E Test (Linux) sandbox:none and sandbox:docker both passed cleanly in the same run.

This PR only modifies TypeScript logic in gemini.tsx (a duplicate cleanup registration removal) with zero OS-specific code paths, so a macOS-only failure is almost certainly a pre-existing flake.

Could you re-trigger the E2E? All other 25 checks pass.

@Adib234
Adib234 added this pull request to the merge queue Mar 27, 2026
Merged via the queue into google-gemini:main with commit bf6dae4 Mar 27, 2026
27 checks passed
keithguerin pushed a commit that referenced this pull request Mar 28, 2026
danzaharia1 pushed a commit that referenced this pull request Mar 30, 2026
warrenzhu25 pushed a commit to warrenzhu25/gemini-cli that referenced this pull request Apr 9, 2026
@sripasg sripasg added the size/m A medium sized PR label Jun 2, 2026
software-0ficial pushed a commit to software-0ficial/gemini-cli that referenced this pull request Jul 9, 2026
@krishdef7
krishdef7 deleted the fix/session-end-double-fire-18019 branch September 26, 2026 06:45
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 help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! priority/p1 Important and should be addressed in the near term. size/m A medium sized PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SessionEnd hook is fired twice on exit

5 participants