fix: improve error message when OAuth succeeds but project ID is required (#21070)

This commit is contained in:
nityam
2026-03-05 00:58:34 +05:30
committed by GitHub
parent ac4e65d669
commit 8f36051f32
5 changed files with 61 additions and 1 deletions

View File

@@ -9,6 +9,7 @@ import { performInitialAuth } from './auth.js';
import {
type Config,
ValidationRequiredError,
ProjectIdRequiredError,
AuthType,
} from '@google/gemini-cli-core';
@@ -116,4 +117,22 @@ describe('auth', () => {
AuthType.LOGIN_WITH_GOOGLE,
);
});
it('should return ProjectIdRequiredError message without "Failed to login" prefix', async () => {
const projectIdError = new ProjectIdRequiredError();
vi.mocked(mockConfig.refreshAuth).mockRejectedValue(projectIdError);
const result = await performInitialAuth(
mockConfig,
AuthType.LOGIN_WITH_GOOGLE,
);
expect(result).toEqual({
authError:
'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',
accountSuspensionInfo: null,
});
expect(result.authError).not.toContain('Failed to login');
expect(mockConfig.refreshAuth).toHaveBeenCalledWith(
AuthType.LOGIN_WITH_GOOGLE,
);
});
});

View File

@@ -10,6 +10,7 @@ import {
getErrorMessage,
ValidationRequiredError,
isAccountSuspendedError,
ProjectIdRequiredError,
} from '@google/gemini-cli-core';
import type { AccountSuspensionInfo } from '../ui/contexts/UIStateContext.js';
@@ -54,6 +55,14 @@ export async function performInitialAuth(
},
};
}
if (e instanceof ProjectIdRequiredError) {
// OAuth succeeded but account setup requires project ID
// Show the error message directly without "Failed to login" prefix
return {
authError: getErrorMessage(e),
accountSuspensionInfo: null,
};
}
return {
authError: `Failed to login. Message: ${getErrorMessage(e)}`,
accountSuspensionInfo: null,

View File

@@ -80,6 +80,7 @@ import {
type ConsentRequestPayload,
type AgentsDiscoveredPayload,
ChangeAuthRequestedError,
ProjectIdRequiredError,
CoreToolCallStatus,
generateSteeringAckMessage,
buildUserSteeringHintPrompt,
@@ -771,6 +772,12 @@ export const AppContainer = (props: AppContainerProps) => {
if (e instanceof ChangeAuthRequestedError) {
return;
}
if (e instanceof ProjectIdRequiredError) {
// OAuth succeeded but account setup requires project ID
// Show the error message directly without "Failed to authenticate" prefix
onAuthError(getErrorMessage(e));
return;
}
onAuthError(
`Failed to authenticate: ${e instanceof Error ? e.message : String(e)}`,
);

View File

@@ -15,7 +15,11 @@ import {
} from 'vitest';
import { renderHook } from '../../test-utils/render.js';
import { useAuthCommand, validateAuthMethodWithSettings } from './useAuth.js';
import { AuthType, type Config } from '@google/gemini-cli-core';
import {
AuthType,
type Config,
ProjectIdRequiredError,
} from '@google/gemini-cli-core';
import { AuthState } from '../types.js';
import type { LoadedSettings } from '../../config/settings.js';
import { waitFor } from '../../test-utils/async.js';
@@ -288,5 +292,21 @@ describe('useAuth', () => {
expect(result.current.authState).toBe(AuthState.Updating);
});
});
it('should handle ProjectIdRequiredError without "Failed to login" prefix', async () => {
const projectIdError = new ProjectIdRequiredError();
(mockConfig.refreshAuth as Mock).mockRejectedValue(projectIdError);
const { result } = renderHook(() =>
useAuthCommand(createSettings(AuthType.LOGIN_WITH_GOOGLE), mockConfig),
);
await waitFor(() => {
expect(result.current.authError).toBe(
'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',
);
expect(result.current.authError).not.toContain('Failed to login');
expect(result.current.authState).toBe(AuthState.Updating);
});
});
});
});

View File

@@ -12,6 +12,7 @@ import {
loadApiKey,
debugLogger,
isAccountSuspendedError,
ProjectIdRequiredError,
} from '@google/gemini-cli-core';
import { getErrorMessage } from '@google/gemini-cli-core';
import { AuthState } from '../types.js';
@@ -143,6 +144,10 @@ export const useAuthCommand = (
appealUrl: suspendedError.appealUrl,
appealLinkText: suspendedError.appealLinkText,
});
} else if (e instanceof ProjectIdRequiredError) {
// OAuth succeeded but account setup requires project ID
// Show the error message directly without "Failed to login" prefix
onAuthError(getErrorMessage(e));
} else {
onAuthError(`Failed to login. Message: ${getErrorMessage(e)}`);
}