Skip to content

Commit 65c7cf5

Browse files
authored
Merge pull request #1376 from QwenLM/fix/missing-error-throw-nonInteractive
fix: exit with non-zero code on API errors in text mode
2 parents 7a82306 + 1591289 commit 65c7cf5

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

packages/cli/src/nonInteractiveCli.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,52 @@ describe('runNonInteractive', () => {
773773
);
774774
});
775775

776+
it('should handle API errors in text mode and exit with error code', async () => {
777+
(mockConfig.getOutputFormat as Mock).mockReturnValue(OutputFormat.TEXT);
778+
setupMetricsMock();
779+
780+
// Simulate an API error event (like 401 unauthorized)
781+
const apiErrorEvent: ServerGeminiStreamEvent = {
782+
type: GeminiEventType.Error,
783+
value: {
784+
error: {
785+
message: '401 Incorrect API key provided',
786+
status: 401,
787+
},
788+
},
789+
};
790+
791+
mockGeminiClient.sendMessageStream.mockReturnValue(
792+
createStreamFromEvents([apiErrorEvent]),
793+
);
794+
795+
let thrownError: Error | null = null;
796+
try {
797+
await runNonInteractive(
798+
mockConfig,
799+
mockSettings,
800+
'Test input',
801+
'prompt-id-api-error',
802+
);
803+
// Should not reach here
804+
expect.fail('Expected error to be thrown');
805+
} catch (error) {
806+
thrownError = error as Error;
807+
}
808+
809+
// Should throw with the API error message
810+
expect(thrownError).toBeTruthy();
811+
expect(thrownError?.message).toContain('401');
812+
expect(thrownError?.message).toContain('Incorrect API key provided');
813+
814+
// Verify error was written to stderr
815+
expect(processStderrSpy).toHaveBeenCalled();
816+
const stderrCalls = processStderrSpy.mock.calls;
817+
const errorOutput = stderrCalls.map((call) => call[0]).join('');
818+
expect(errorOutput).toContain('401');
819+
expect(errorOutput).toContain('Incorrect API key provided');
820+
});
821+
776822
it('should handle FatalInputError with custom exit code in JSON format', async () => {
777823
(mockConfig.getOutputFormat as Mock).mockReturnValue(OutputFormat.JSON);
778824
setupMetricsMock();

packages/cli/src/nonInteractiveCli.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,8 @@ export async function runNonInteractive(
312312
config.getContentGeneratorConfig()?.authType,
313313
);
314314
process.stderr.write(`${errorText}\n`);
315+
// Throw error to exit with non-zero code
316+
throw new Error(errorText);
315317
}
316318
}
317319
}

0 commit comments

Comments
 (0)