Fix for silent failures in non-interactive mode (#19905)

This commit is contained in:
owenofbrien
2026-02-23 11:35:13 -06:00
committed by GitHub
parent 6628cbb39d
commit fa9aee2bf0
4 changed files with 27 additions and 7 deletions
+6 -4
View File
@@ -13,6 +13,7 @@ import {
getAllMCPServerStatuses, getAllMCPServerStatuses,
MCPServerStatus, MCPServerStatus,
isNodeError, isNodeError,
getErrorMessage,
parseAndFormatApiError, parseAndFormatApiError,
safeLiteralReplace, safeLiteralReplace,
DEFAULT_GUI_EDITOR, DEFAULT_GUI_EDITOR,
@@ -727,16 +728,17 @@ export class Task {
// Block scope for lexical declaration // Block scope for lexical declaration
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const errorEvent = event as ServerGeminiErrorEvent; // Type assertion const errorEvent = event as ServerGeminiErrorEvent; // Type assertion
const errorMessage = const errorMessage = errorEvent.value?.error
errorEvent.value?.error.message ?? 'Unknown error from LLM stream'; ? getErrorMessage(errorEvent.value.error)
: 'Unknown error from LLM stream';
logger.error( logger.error(
'[Task] Received error event from LLM stream:', '[Task] Received error event from LLM stream:',
errorMessage, errorMessage,
); );
let errMessage = `Unknown error from LLM stream: ${JSON.stringify(event)}`; let errMessage = `Unknown error from LLM stream: ${JSON.stringify(event)}`;
if (errorEvent.value) { if (errorEvent.value?.error) {
errMessage = parseAndFormatApiError(errorEvent.value); errMessage = parseAndFormatApiError(errorEvent.value.error);
} }
this.cancelPendingTools(`LLM stream error: ${errorMessage}`); this.cancelPendingTools(`LLM stream error: ${errorMessage}`);
this.setTaskStateAndPublishUpdate( this.setTaskStateAndPublishUpdate(
+16 -1
View File
@@ -36,7 +36,21 @@ process.on('uncaughtException', (error) => {
}); });
main().catch(async (error) => { main().catch(async (error) => {
await runExitCleanup(); // Set a timeout to force exit if cleanup hangs
const cleanupTimeout = setTimeout(() => {
writeToStderr('Cleanup timed out, forcing exit...\n');
process.exit(1);
}, 5000);
try {
await runExitCleanup();
} catch (cleanupError) {
writeToStderr(
`Error during final cleanup: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}\n`,
);
} finally {
clearTimeout(cleanupTimeout);
}
if (error instanceof FatalError) { if (error instanceof FatalError) {
let errorMessage = error.message; let errorMessage = error.message;
@@ -46,6 +60,7 @@ main().catch(async (error) => {
writeToStderr(errorMessage + '\n'); writeToStderr(errorMessage + '\n');
process.exit(error.exitCode); process.exit(error.exitCode);
} }
writeToStderr('An unexpected critical error occurred:'); writeToStderr('An unexpected critical error occurred:');
if (error instanceof Error) { if (error instanceof Error) {
writeToStderr(error.stack + '\n'); writeToStderr(error.stack + '\n');
+4 -1
View File
@@ -261,7 +261,10 @@ describe('Turn', () => {
const errorEvent = events[0] as ServerGeminiErrorEvent; const errorEvent = events[0] as ServerGeminiErrorEvent;
expect(errorEvent.type).toBe(GeminiEventType.Error); expect(errorEvent.type).toBe(GeminiEventType.Error);
expect(errorEvent.value).toEqual({ expect(errorEvent.value).toEqual({
error: { message: 'API Error', status: undefined }, error: {
message: 'API Error',
status: undefined,
},
}); });
expect(turn.getDebugResponses().length).toBe(0); expect(turn.getDebugResponses().length).toBe(0);
expect(reportError).toHaveBeenCalledWith( expect(reportError).toHaveBeenCalledWith(
+1 -1
View File
@@ -116,7 +116,7 @@ export interface StructuredError {
} }
export interface GeminiErrorEventValue { export interface GeminiErrorEventValue {
error: StructuredError; error: unknown;
} }
export interface GeminiFinishedEventValue { export interface GeminiFinishedEventValue {