diff --git a/packages/core/src/services/chatRecordingService.test.ts b/packages/core/src/services/chatRecordingService.test.ts index cc3e174cf0..d87ab85ef5 100644 --- a/packages/core/src/services/chatRecordingService.test.ts +++ b/packages/core/src/services/chatRecordingService.test.ts @@ -1059,6 +1059,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 533a7a7459..a1d4392c65 100644 --- a/packages/core/src/services/chatRecordingService.ts +++ b/packages/core/src/services/chatRecordingService.ts @@ -46,6 +46,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, @@ -517,6 +525,10 @@ export class ChatRecordingService { if (isNodeError(error) && error.code === 'ENOSPC') { this.conversationFile = null; debugLogger.warn(ENOSPC_WARNING_MESSAGE); + } else if (error instanceof RangeError || error instanceof TypeError) { + this.conversationFile = null; + const message = error instanceof RangeError ? RANGE_WARNING_MESSAGE : 'Chat recording disabled: Conversation data could not be serialized.'; + debugLogger.warn(message, error); } else { throw error; }