mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-29 15:30:40 -07:00
fix(core): explicitly set error names to avoid bundling renaming issues (#23913)
This commit is contained in:
@@ -19,6 +19,7 @@ import {
|
||||
debugLogger,
|
||||
coreEvents,
|
||||
getErrorMessage,
|
||||
getErrorType,
|
||||
} from '@google/gemini-cli-core';
|
||||
import { runSyncCleanup } from './cleanup.js';
|
||||
|
||||
@@ -82,7 +83,7 @@ export function handleError(
|
||||
timestamp: new Date().toISOString(),
|
||||
status: 'error',
|
||||
error: {
|
||||
type: error instanceof Error ? error.constructor.name : 'Error',
|
||||
type: getErrorType(error),
|
||||
message: errorMessage,
|
||||
},
|
||||
stats: streamFormatter.convertToStreamStats(metrics, 0),
|
||||
@@ -177,7 +178,7 @@ export function handleCancellationError(config: Config): never {
|
||||
timestamp: new Date().toISOString(),
|
||||
status: 'error',
|
||||
error: {
|
||||
type: 'FatalCancellationError',
|
||||
type: getErrorType(cancellationError),
|
||||
message: cancellationError.message,
|
||||
},
|
||||
stats: streamFormatter.convertToStreamStats(metrics, 0),
|
||||
@@ -218,7 +219,7 @@ export function handleMaxTurnsExceededError(config: Config): never {
|
||||
timestamp: new Date().toISOString(),
|
||||
status: 'error',
|
||||
error: {
|
||||
type: 'FatalTurnLimitedError',
|
||||
type: getErrorType(maxTurnsError),
|
||||
message: maxTurnsError.message,
|
||||
},
|
||||
stats: streamFormatter.convertToStreamStats(metrics, 0),
|
||||
|
||||
@@ -32,6 +32,7 @@ export class ProjectIdRequiredError extends Error {
|
||||
super(
|
||||
'This account requires setting the GOOGLE_CLOUD_PROJECT or GOOGLE_CLOUD_PROJECT_ID env var. See https://goo.gle/gemini-cli-auth-docs#workspace-gca',
|
||||
);
|
||||
this.name = 'ProjectIdRequiredError';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +43,7 @@ export class ProjectIdRequiredError extends Error {
|
||||
export class ValidationCancelledError extends Error {
|
||||
constructor() {
|
||||
super('User cancelled account validation');
|
||||
this.name = 'ValidationCancelledError';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +53,7 @@ export class IneligibleTierError extends Error {
|
||||
constructor(ineligibleTiers: IneligibleTier[]) {
|
||||
const reasons = ineligibleTiers.map((t) => t.reasonMessage).join(', ');
|
||||
super(reasons);
|
||||
this.name = 'IneligibleTierError';
|
||||
this.ineligibleTiers = ineligibleTiers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,12 +355,29 @@ describe('getErrorType', () => {
|
||||
expect(getErrorType(undefined)).toBe('unknown');
|
||||
});
|
||||
|
||||
it('should strip leading underscores from error names', () => {
|
||||
class _GaxiosError extends Error {}
|
||||
it('should use explicitly set error names', () => {
|
||||
class _GaxiosError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'GaxiosError';
|
||||
}
|
||||
}
|
||||
expect(getErrorType(new _GaxiosError('test'))).toBe('GaxiosError');
|
||||
|
||||
const errorWithUnderscoreName = new Error('test');
|
||||
errorWithUnderscoreName.name = '_CodeBuddyError';
|
||||
expect(getErrorType(errorWithUnderscoreName)).toBe('CodeBuddyError');
|
||||
class BadRequestError3 extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'BadRequestError';
|
||||
}
|
||||
}
|
||||
expect(getErrorType(new BadRequestError3('test'))).toBe('BadRequestError');
|
||||
|
||||
class _AbortError2 extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'AbortError';
|
||||
}
|
||||
}
|
||||
expect(getErrorType(new _AbortError2('test'))).toBe('AbortError');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -57,9 +57,11 @@ export function getErrorMessage(error: unknown): string {
|
||||
export function getErrorType(error: unknown): string {
|
||||
if (!(error instanceof Error)) return 'unknown';
|
||||
|
||||
// Return constructor name if the generic 'Error' name is used (for custom errors)
|
||||
// Use the constructor name if the standard error name is missing or generic.
|
||||
const name =
|
||||
error.name === 'Error' ? (error.constructor?.name ?? 'Error') : error.name;
|
||||
error.name && error.name !== 'Error'
|
||||
? error.name
|
||||
: (error.constructor?.name ?? 'Error');
|
||||
|
||||
// Strip leading underscore from error names. Bundlers like esbuild sometimes
|
||||
// rename classes to avoid scope collisions.
|
||||
@@ -72,42 +74,50 @@ export class FatalError extends Error {
|
||||
readonly exitCode: number,
|
||||
) {
|
||||
super(message);
|
||||
this.name = 'FatalError';
|
||||
}
|
||||
}
|
||||
|
||||
export class FatalAuthenticationError extends FatalError {
|
||||
constructor(message: string) {
|
||||
super(message, 41);
|
||||
this.name = 'FatalAuthenticationError';
|
||||
}
|
||||
}
|
||||
export class FatalInputError extends FatalError {
|
||||
constructor(message: string) {
|
||||
super(message, 42);
|
||||
this.name = 'FatalInputError';
|
||||
}
|
||||
}
|
||||
export class FatalSandboxError extends FatalError {
|
||||
constructor(message: string) {
|
||||
super(message, 44);
|
||||
this.name = 'FatalSandboxError';
|
||||
}
|
||||
}
|
||||
export class FatalConfigError extends FatalError {
|
||||
constructor(message: string) {
|
||||
super(message, 52);
|
||||
this.name = 'FatalConfigError';
|
||||
}
|
||||
}
|
||||
export class FatalTurnLimitedError extends FatalError {
|
||||
constructor(message: string) {
|
||||
super(message, 53);
|
||||
this.name = 'FatalTurnLimitedError';
|
||||
}
|
||||
}
|
||||
export class FatalToolExecutionError extends FatalError {
|
||||
constructor(message: string) {
|
||||
super(message, 54);
|
||||
this.name = 'FatalToolExecutionError';
|
||||
}
|
||||
}
|
||||
export class FatalCancellationError extends FatalError {
|
||||
constructor(message: string) {
|
||||
super(message, 130); // Standard exit code for SIGINT
|
||||
this.name = 'FatalCancellationError';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +128,12 @@ export class CanceledError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
export class ForbiddenError extends Error {}
|
||||
export class ForbiddenError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'ForbiddenError';
|
||||
}
|
||||
}
|
||||
export class AccountSuspendedError extends ForbiddenError {
|
||||
readonly appealUrl?: string;
|
||||
readonly appealLinkText?: string;
|
||||
@@ -130,8 +145,18 @@ export class AccountSuspendedError extends ForbiddenError {
|
||||
this.appealLinkText = metadata?.['appeal_url_link_text'];
|
||||
}
|
||||
}
|
||||
export class UnauthorizedError extends Error {}
|
||||
export class BadRequestError extends Error {}
|
||||
export class UnauthorizedError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'UnauthorizedError';
|
||||
}
|
||||
}
|
||||
export class BadRequestError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'BadRequestError';
|
||||
}
|
||||
}
|
||||
|
||||
export class ChangeAuthRequestedError extends Error {
|
||||
constructor() {
|
||||
@@ -264,10 +289,7 @@ export function isAuthenticationError(error: unknown): boolean {
|
||||
}
|
||||
|
||||
// Check for UnauthorizedError class (from MCP SDK or our own)
|
||||
if (
|
||||
error instanceof Error &&
|
||||
error.constructor.name === 'UnauthorizedError'
|
||||
) {
|
||||
if (error instanceof Error && error.name === 'UnauthorizedError') {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user