mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 05:12:55 -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,
|
debugLogger,
|
||||||
coreEvents,
|
coreEvents,
|
||||||
getErrorMessage,
|
getErrorMessage,
|
||||||
|
getErrorType,
|
||||||
} from '@google/gemini-cli-core';
|
} from '@google/gemini-cli-core';
|
||||||
import { runSyncCleanup } from './cleanup.js';
|
import { runSyncCleanup } from './cleanup.js';
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@ export function handleError(
|
|||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
status: 'error',
|
status: 'error',
|
||||||
error: {
|
error: {
|
||||||
type: error instanceof Error ? error.constructor.name : 'Error',
|
type: getErrorType(error),
|
||||||
message: errorMessage,
|
message: errorMessage,
|
||||||
},
|
},
|
||||||
stats: streamFormatter.convertToStreamStats(metrics, 0),
|
stats: streamFormatter.convertToStreamStats(metrics, 0),
|
||||||
@@ -177,7 +178,7 @@ export function handleCancellationError(config: Config): never {
|
|||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
status: 'error',
|
status: 'error',
|
||||||
error: {
|
error: {
|
||||||
type: 'FatalCancellationError',
|
type: getErrorType(cancellationError),
|
||||||
message: cancellationError.message,
|
message: cancellationError.message,
|
||||||
},
|
},
|
||||||
stats: streamFormatter.convertToStreamStats(metrics, 0),
|
stats: streamFormatter.convertToStreamStats(metrics, 0),
|
||||||
@@ -218,7 +219,7 @@ export function handleMaxTurnsExceededError(config: Config): never {
|
|||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
status: 'error',
|
status: 'error',
|
||||||
error: {
|
error: {
|
||||||
type: 'FatalTurnLimitedError',
|
type: getErrorType(maxTurnsError),
|
||||||
message: maxTurnsError.message,
|
message: maxTurnsError.message,
|
||||||
},
|
},
|
||||||
stats: streamFormatter.convertToStreamStats(metrics, 0),
|
stats: streamFormatter.convertToStreamStats(metrics, 0),
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export class ProjectIdRequiredError extends Error {
|
|||||||
super(
|
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 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 {
|
export class ValidationCancelledError extends Error {
|
||||||
constructor() {
|
constructor() {
|
||||||
super('User cancelled account validation');
|
super('User cancelled account validation');
|
||||||
|
this.name = 'ValidationCancelledError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,6 +53,7 @@ export class IneligibleTierError extends Error {
|
|||||||
constructor(ineligibleTiers: IneligibleTier[]) {
|
constructor(ineligibleTiers: IneligibleTier[]) {
|
||||||
const reasons = ineligibleTiers.map((t) => t.reasonMessage).join(', ');
|
const reasons = ineligibleTiers.map((t) => t.reasonMessage).join(', ');
|
||||||
super(reasons);
|
super(reasons);
|
||||||
|
this.name = 'IneligibleTierError';
|
||||||
this.ineligibleTiers = ineligibleTiers;
|
this.ineligibleTiers = ineligibleTiers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -355,12 +355,29 @@ describe('getErrorType', () => {
|
|||||||
expect(getErrorType(undefined)).toBe('unknown');
|
expect(getErrorType(undefined)).toBe('unknown');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should strip leading underscores from error names', () => {
|
it('should use explicitly set error names', () => {
|
||||||
class _GaxiosError extends Error {}
|
class _GaxiosError extends Error {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'GaxiosError';
|
||||||
|
}
|
||||||
|
}
|
||||||
expect(getErrorType(new _GaxiosError('test'))).toBe('GaxiosError');
|
expect(getErrorType(new _GaxiosError('test'))).toBe('GaxiosError');
|
||||||
|
|
||||||
const errorWithUnderscoreName = new Error('test');
|
class BadRequestError3 extends Error {
|
||||||
errorWithUnderscoreName.name = '_CodeBuddyError';
|
constructor(message: string) {
|
||||||
expect(getErrorType(errorWithUnderscoreName)).toBe('CodeBuddyError');
|
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 {
|
export function getErrorType(error: unknown): string {
|
||||||
if (!(error instanceof Error)) return 'unknown';
|
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 =
|
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
|
// Strip leading underscore from error names. Bundlers like esbuild sometimes
|
||||||
// rename classes to avoid scope collisions.
|
// rename classes to avoid scope collisions.
|
||||||
@@ -72,42 +74,50 @@ export class FatalError extends Error {
|
|||||||
readonly exitCode: number,
|
readonly exitCode: number,
|
||||||
) {
|
) {
|
||||||
super(message);
|
super(message);
|
||||||
|
this.name = 'FatalError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FatalAuthenticationError extends FatalError {
|
export class FatalAuthenticationError extends FatalError {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message, 41);
|
super(message, 41);
|
||||||
|
this.name = 'FatalAuthenticationError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class FatalInputError extends FatalError {
|
export class FatalInputError extends FatalError {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message, 42);
|
super(message, 42);
|
||||||
|
this.name = 'FatalInputError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class FatalSandboxError extends FatalError {
|
export class FatalSandboxError extends FatalError {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message, 44);
|
super(message, 44);
|
||||||
|
this.name = 'FatalSandboxError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class FatalConfigError extends FatalError {
|
export class FatalConfigError extends FatalError {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message, 52);
|
super(message, 52);
|
||||||
|
this.name = 'FatalConfigError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class FatalTurnLimitedError extends FatalError {
|
export class FatalTurnLimitedError extends FatalError {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message, 53);
|
super(message, 53);
|
||||||
|
this.name = 'FatalTurnLimitedError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class FatalToolExecutionError extends FatalError {
|
export class FatalToolExecutionError extends FatalError {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message, 54);
|
super(message, 54);
|
||||||
|
this.name = 'FatalToolExecutionError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class FatalCancellationError extends FatalError {
|
export class FatalCancellationError extends FatalError {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message, 130); // Standard exit code for SIGINT
|
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 {
|
export class AccountSuspendedError extends ForbiddenError {
|
||||||
readonly appealUrl?: string;
|
readonly appealUrl?: string;
|
||||||
readonly appealLinkText?: string;
|
readonly appealLinkText?: string;
|
||||||
@@ -130,8 +145,18 @@ export class AccountSuspendedError extends ForbiddenError {
|
|||||||
this.appealLinkText = metadata?.['appeal_url_link_text'];
|
this.appealLinkText = metadata?.['appeal_url_link_text'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class UnauthorizedError extends Error {}
|
export class UnauthorizedError extends Error {
|
||||||
export class BadRequestError 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 {
|
export class ChangeAuthRequestedError extends Error {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -264,10 +289,7 @@ export function isAuthenticationError(error: unknown): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for UnauthorizedError class (from MCP SDK or our own)
|
// Check for UnauthorizedError class (from MCP SDK or our own)
|
||||||
if (
|
if (error instanceof Error && error.name === 'UnauthorizedError') {
|
||||||
error instanceof Error &&
|
|
||||||
error.constructor.name === 'UnauthorizedError'
|
|
||||||
) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user