diff --git a/packages/core/src/core/logger.test.ts b/packages/core/src/core/logger.test.ts index dd150aec87f..e0b70a76e37 100644 --- a/packages/core/src/core/logger.test.ts +++ b/packages/core/src/core/logger.test.ts @@ -567,6 +567,25 @@ describe('Logger', () => { ); }); + it.each([ + ['null', null], + ['number', 123], + ])( + 'should return an empty history if history is %s instead of an array (#29194)', + async (_label: string, badHistory: unknown) => { + const taggedFilePath = path.join( + TEST_GEMINI_DIR, + 'checkpoint-wrong-shape.json', + ); + await fs.writeFile( + taggedFilePath, + JSON.stringify({ history: badHistory }), + ); + const loadedCheckpoint = await logger.loadCheckpoint('wrong-shape'); + expect(loadedCheckpoint).toEqual({ history: [] }); + }, + ); + it('should return an empty history if logger is not initialized', async () => { const uninitializedLogger = new Logger( testSessionId, diff --git a/packages/core/src/core/logger.ts b/packages/core/src/core/logger.ts index 5a937b4edc8..36655d27754 100644 --- a/packages/core/src/core/logger.ts +++ b/packages/core/src/core/logger.ts @@ -367,8 +367,13 @@ export class Logger { parsedContent !== null && 'history' in parsedContent ) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion - return parsedContent as Checkpoint; + const history: unknown = parsedContent.history; + // A valid-JSON file with a non-array history (crash mid-save, full + // disk, hand edit) must degrade like any other corrupt file (#29194). + if (Array.isArray(history)) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion + return parsedContent as Checkpoint; + } } debugLogger.warn(