Skip to content

fix(acp): don't start a fresh chat before resuming, it poisons the session file - #28744

Closed
PranavMishra28 wants to merge 2 commits into
google-gemini:mainfrom
PranavMishra28:fix/acp-load-poisons-session-file
Closed

fix(acp): don't start a fresh chat before resuming, it poisons the session file#28744
PranavMishra28 wants to merge 2 commits into
google-gemini:mainfrom
PranavMishra28:fix/acp-load-poisons-session-file

Conversation

@PranavMishra28

@PranavMishra28 PranavMishra28 commented Aug 9, 2026

Copy link
Copy Markdown

Partially addresses #28693 — see the correction below; this removes one of two fresh-chat starts on the load path, not both.

Correction (2026-08-10). loadSession calls initializeSessionConfig first, and that ends with await config.initialize(), which itself calls this._geminiClient.initialize(). So there were two fresh-chat starts ahead of resumeChat, and this PR only removes the second. The test here could not catch that because mockConfig.initialize is a stub. #28767 fixes the underlying cause by handing the resumed session data to config.initialize(); the remaining ACP work after that is to resolve the session before initializeSessionConfig and pass it through. The removal in this PR is still correct on its own merits — resumeChat already does everything initialize() does — but it does not close #28693 by itself.

Problem

loadSession called geminiClient.initialize() immediately before resumeChat():

const geminiClient = config.getGeminiClient();
await geminiClient.initialize();          // starts a chat with NO resumed session data
await geminiClient.resumeChat(clientHistory, { conversation: sessionData, filePath: sessionPath });

initialize() is this.chat = await this.startChat() with no resumedSessionData, so ChatRecordingService.initialize(undefined) takes the fresh-conversation branch and writes a metadata header plus a $set checkpoint.

The recording filename is keyed on the UTC minute and the session id prefix — session-<UTC-minute>-<id[0:8]>.jsonl (chatRecordingService.ts:495-519). So when the load happens in the same UTC minute the session was created, that append lands in the session's own conversation file. The checkpoint buries the conversation in the fold, hasResumableContent flips false, the session is filtered out of the listing, and the load fails with No previous sessions found for this project — after durably destroying the session's resumability, so every later load for that id fails too.

No crash is required; it reproduces after a clean exit. Automated clients that reconnect immediately land in this window, while a human retrying minutes later lands in a different minute and sees loads succeed — which is why it read as intermittent or environment-dependent.

Credit to @realtonyyoung for the repro and for re-root-causing it; I'd earlier ruled out four candidate mechanisms on the issue and the load path was what was left.

Approach

Remove the initialize() call. resumeChat already does everything it does — it sets this.chat via startChat(history, resumedSessionData) and calls updateTelemetryTokenCount() — so the call was redundant as well as destructive. One line out, plus a comment recording why it must not come back.

This deliberately does not change the filename scheme. Minute-precision plus an 8-char id prefix is a real collision surface, but widening it would change where existing sessions are looked up, and it isn't needed here: nothing should be writing a fresh-conversation header during a load in the first place.

How tested

  • resumes without first starting a fresh chat for the same session id asserts the client is resumed directly with the resolved session data and never initialized for a fresh chat. It fails on the parent commit with expected "spy" to not be called at all, but actually been called 1 times.
  • Full ACP suite: 92 passed across 10 files.
  • eslint --max-warnings 0 and prettier --check clean; npm run typecheck exit 0. The repo's pre-commit hook ran clean on the staged files.

Developed with Claude Code; reviewed and tested by Pranav before marking ready for review.

…ssion file

Closes google-gemini#28693.

`loadSession` called `geminiClient.initialize()` immediately before
`resumeChat()`. `initialize()` starts a chat with no resumed session data, so it
initializes chat recording for a *fresh* conversation and writes a metadata
header plus a `$set` checkpoint.

The recording filename is keyed on the UTC minute and the session id prefix
(`session-<UTC-minute>-<id[0:8]>.jsonl`), so a load issued in the same minute the
session was created resolves to the session's own file. The checkpoint buries the
existing conversation in the fold, `hasResumableContent` flips false, the session
drops out of the listing, and the load fails with "No previous sessions found for
this project" — after durably destroying the session's resumability, so every
later load for that id fails too.

No crash is required; it reproduces after a clean exit. Automated clients that
reconnect immediately land in this window, while a human retrying minutes later
lands in a different minute and sees it work, which is why it looked intermittent.

`resumeChat` already does everything `initialize()` does, including
`updateTelemetryTokenCount()`, so the call was redundant as well as destructive
and is simply removed.

Tests: `resumes without first starting a fresh chat for the same session id`
asserts the client is resumed directly and never initialized for a fresh chat. It
fails on the parent commit with "expected spy to not be called at all, but
actually been called 1 times". Full ACP suite 92 passed across 10 files, eslint
--max-warnings 0 and prettier clean, npm run typecheck exit 0.

Developed with Claude Code; reviewed and tested by Pranav before marking ready for review.
@PranavMishra28
PranavMishra28 requested a review from a team as a code owner August 9, 2026 20:16
@github-actions github-actions Bot added the size/m A medium sized PR label Aug 9, 2026
@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 critical issue where loading a chat session could inadvertently corrupt the session file, rendering it unresumable. By removing a redundant initialization step that incorrectly triggered fresh-conversation logic, the fix ensures that sessions are resumed directly without modifying their internal structure. This change improves the reliability of session persistence and prevents intermittent failures during rapid session reconnection.

Highlights

  • Removed redundant initialization: Removed the call to geminiClient.initialize() during session loading, as it was causing destructive side effects by treating resumed sessions as fresh conversations.
  • Fixed session corruption: Prevented the session file from being corrupted by metadata headers and checkpoints that previously caused sessions to disappear from the listing if loaded within the same UTC minute of creation.
  • Added regression test: Added a new test case in acpResume.test.ts to ensure that geminiClient.initialize() is not called when resuming a session.
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 the 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 counterproductive. 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.

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.

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

📊 PR Size: size/M

  • Lines changed: 53
  • Additions: +52
  • Deletions: -1
  • Files changed: 2

@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 removes a redundant and destructive call to geminiClient.initialize() prior to calling geminiClient.resumeChat() in AcpSessionManager. The redundant call was causing issues by starting a fresh chat and overwriting session metadata when resuming a session within the same minute. A detailed explanatory comment has been added to the code, and a new unit test has been introduced in acpResume.test.ts to verify that initialize() is not called during session resumption. There are no review comments, and I have no additional feedback to provide.

@PranavMishra28

Copy link
Copy Markdown
Author

correction on my own PR: this removal is necessary but it is not sufficient, and I want that on the record before anyone merges it thinking the path is closed.

loadSession calls initializeSessionConfig first, and that ends with await config.initialize() (acpSessionManager.ts#L279). Config._initialize() finishes with await this._geminiClient.initialize() (config.ts#L1560), which is the same this.chat = await this.startChat() with no resumed data. So there were two fresh-chat starts ahead of resumeChat, not one, and this PR only deletes the second.

my test could not catch it because mockConfig.initialize is a stub, so the config path does nothing in that suite. that is a real gap in the test, not just in the fix — asserting geminiClient.initialize was not called says nothing about what config.initialize did.

the reason it still matters: config.initialize() runs with the ACP session id, so chat recording opens session-<UTC minute>-<sessionId[0:8]>.jsonl, which is the same collision this PR describes.

I opened #28767 for the underlying cause — config.initialize() takes the resumed session data and hands it to GeminiClient.initialize(), so recording reopens the existing file instead of starting a new one. it fixes the CLI --resume path (#27368, #27877), where the same defect destroys sessions through retention cleanup.

once that lands, the ACP fix is a small follow-up: resolve the session before initializeSessionConfig and pass the resumed data into config.initialize(). I can do that in this PR or a new one, whichever reviewers prefer. this one is still worth keeping on its own merits — resumeChat already does everything initialize() does, so the call it removes is pure redundancy — but it should not be described as closing #28693 by itself, and I have corrected the description above.

@gemini-cli

gemini-cli Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Hi there! Thank you for your interest in contributing to Gemini CLI.

To ensure we maintain high code quality and focus on our prioritized roadmap, we only guarantee review and consideration of pull requests for issues that are explicitly labeled as 'help wanted'.

This PR will be closed in 7 days if it remains without that designation. We encourage you to find and contribute to existing 'help wanted' issues in our backlog! Thank you for your understanding.

@gemini-cli

gemini-cli Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

This pull request is being closed as it has been open for 14 days without a 'help wanted' designation. We encourage you to find and contribute to existing 'help wanted' issues in our backlog! Thank you for your understanding.

@gemini-cli gemini-cli Bot closed this Aug 24, 2026
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 priority/p1 Important and should be addressed in the near term. size/m A medium sized PR status/pr-nudge-sent

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ACP: session/load in the same UTC minute as session/new fails with "No previous sessions found" — and durably destroys the session's resumability

1 participant