From 68b28b5ca566ee9384324b1dde7ce4de7d84cc46 Mon Sep 17 00:00:00 2001 From: Enjoy Kumawat Date: Tue, 14 Apr 2026 13:16:50 +0530 Subject: [PATCH 1/2] fix: handle RangeError when conversation exceeds JSON serializable size When JSON.stringify is called on a very large conversation object, V8 can throw a RangeError ('Invalid string length'). This was not caught by the existing error handler, causing an unhandled promise rejection that crashed the CLI. Mirror the existing ENOSPC pattern: catch RangeError in appendRecord, disable chat recording, emit a warning, and allow the conversation to continue. Fixes #24902 --- .../src/services/chatRecordingService.test.ts | 49 +++++++++++++++++++ .../core/src/services/chatRecordingService.ts | 11 +++++ 2 files changed, 60 insertions(+) diff --git a/packages/core/src/services/chatRecordingService.test.ts b/packages/core/src/services/chatRecordingService.test.ts index 94b9c61c7a..0f897a2ed0 100644 --- a/packages/core/src/services/chatRecordingService.test.ts +++ b/packages/core/src/services/chatRecordingService.test.ts @@ -956,6 +956,55 @@ describe('ChatRecordingService', () => { }); }); + describe('RangeError (conversation too large) graceful degradation - issue #24902', () => { + it('should disable recording and not throw when RangeError occurs during appendRecord', async () => { + await chatRecordingService.initialize(); + + vi.mocked(fs.appendFileSync).mockImplementation(() => { + throw new RangeError('Invalid string length'); + }); + + expect(() => + chatRecordingService.recordMessage({ + type: 'user', + content: 'Hello', + model: 'gemini-pro', + }), + ).not.toThrow(); + + expect(chatRecordingService.getConversationFilePath()).toBeNull(); + }); + + it('should skip recording operations after RangeError disables recording', async () => { + await chatRecordingService.initialize(); + + vi.mocked(fs.appendFileSync) + .mockImplementationOnce(() => { + throw new RangeError('Invalid string length'); + }) + .mockImplementation(() => {}); + + chatRecordingService.recordMessage({ + type: 'user', + content: 'Hello', + model: 'gemini-pro', + }); + + // Recording should be disabled after RangeError + expect(chatRecordingService.getConversationFilePath()).toBeNull(); + + // Subsequent records should silently no-op + const appendSpy = vi.mocked(fs.appendFileSync); + const callsBefore = appendSpy.mock.calls.length; + chatRecordingService.recordMessage({ + type: 'user', + content: 'Second message', + model: 'gemini-pro', + }); + expect(appendSpy.mock.calls.length).toBe(callsBefore); + }); + }); + describe('updateMessagesFromHistory', () => { beforeEach(async () => { await chatRecordingService.initialize(); diff --git a/packages/core/src/services/chatRecordingService.ts b/packages/core/src/services/chatRecordingService.ts index cab67f80a1..efdc1f8d29 100644 --- a/packages/core/src/services/chatRecordingService.ts +++ b/packages/core/src/services/chatRecordingService.ts @@ -47,6 +47,14 @@ const ENOSPC_WARNING_MESSAGE = 'The conversation will continue but will not be saved to disk. ' + 'Free up disk space and restart to enable recording.'; +/** + * Warning message shown when recording is disabled due to conversation exceeding + * the maximum serializable size. + */ +const RANGE_WARNING_MESSAGE = + 'Chat recording disabled: Conversation exceeded maximum serializable size. ' + + 'The conversation will continue but will not be saved to disk.'; + function hasProperty( obj: unknown, prop: T, @@ -397,6 +405,9 @@ export class ChatRecordingService { if (isNodeError(error) && error.code === 'ENOSPC') { this.conversationFile = null; debugLogger.warn(ENOSPC_WARNING_MESSAGE); + } else if (error instanceof RangeError) { + this.conversationFile = null; + debugLogger.warn(RANGE_WARNING_MESSAGE); } else { throw error; } From d28ab56dd278b65f2f26421652e65eeade194eaf Mon Sep 17 00:00:00 2001 From: Enjoy Kumawat <121963208+enjoykumawat@users.noreply.github.com> Date: Tue, 14 Apr 2026 13:27:39 +0530 Subject: [PATCH 2/2] Update packages/core/src/services/chatRecordingService.ts Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- packages/core/src/services/chatRecordingService.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/core/src/services/chatRecordingService.ts b/packages/core/src/services/chatRecordingService.ts index efdc1f8d29..0e1fd62cac 100644 --- a/packages/core/src/services/chatRecordingService.ts +++ b/packages/core/src/services/chatRecordingService.ts @@ -405,9 +405,10 @@ export class ChatRecordingService { if (isNodeError(error) && error.code === 'ENOSPC') { this.conversationFile = null; debugLogger.warn(ENOSPC_WARNING_MESSAGE); - } else if (error instanceof RangeError) { + } else if (error instanceof RangeError || error instanceof TypeError) { this.conversationFile = null; - debugLogger.warn(RANGE_WARNING_MESSAGE); + const message = error instanceof RangeError ? RANGE_WARNING_MESSAGE : 'Chat recording disabled: Conversation data could not be serialized.'; + debugLogger.warn(message, error); } else { throw error; }