google-gemini/gemini-cli · warning · FatalCancellationError
Authentication cancelled by user.
Error message
Authentication cancelled by user.
What it means
Before opening the browser for the OAuth flow, getConsentForOauth prompts the user; if they decline, the provider throws FatalCancellationError('Authentication cancelled by user.'). This is an intentional user action, not a system failure. FatalCancellationError signals that retrying the same flow without a different user decision will not help, so callers should treat it as terminal for this attempt.
Source
Thrown at packages/core/src/agents/auth-provider/oauth2-provider.ts:249
};
const pkceParams = generatePKCEParams();
const preferredPort = getPortFromUrl(flowConfig.redirectUri);
const callbackServer = startCallbackServer(pkceParams.state, preferredPort);
const redirectPort = await callbackServer.port;
const authUrl = buildAuthorizationUrl(
flowConfig,
pkceParams,
redirectPort,
/* resource= */ undefined, // No MCP resource parameter for A2A.
);
const consent = await getConsentForOauth(
`Authentication required for A2A agent: '${this.agentName}'.`,
);
if (!consent) {
throw new FatalCancellationError('Authentication cancelled by user.');
}
coreEvents.emitFeedback(
'info',
`→ Opening your browser for OAuth sign-in...
` +
`If the browser does not open, copy and paste this URL into your browser:
` +
`${authUrl}
` +
`💡 TIP: Triple-click to select the entire URL, then copy and paste it into your browser.
` +
`⚠️ Make sure to copy the COMPLETE URL - it may wrap across multiple lines.`,
);
try {View on GitHub (pinned to 5024443c72)
Solutions
- Catch FatalCancellationError specifically and surface a clean 'cancelled' message rather than an error.
- Re-invoke the flow only when the user explicitly requests it again.
- For non-interactive contexts, pre-seed a stored token to skip the consent prompt.
- Do not auto-retry on this error; it is not transient.
Example fix
// before
const token = await provider.getToken();
// after
try {
const token = await provider.getToken();
} catch (e) {
if (e instanceof FatalCancellationError) {
console.log('User cancelled authentication.');
return;
}
throw e;
} Defensive patterns
Strategy: try-catch
Type guard
function isAuthCancelled(e: unknown): boolean {
return e instanceof FatalCancellationError
&& /cancelled by user/i.test(e.message);
} Try / catch
try {
return await provider.getToken();
} catch (e) {
if (e instanceof FatalCancellationError) {
// user declined - do not retry automatically
return { cancelled: true } as const;
}
throw e;
} Prevention
- Catch FatalCancellationError separately and surface a clean cancellation.
- Never auto-retry user cancellations; they are intentional and terminal.
- In non-interactive contexts, pre-seed stored tokens to avoid the consent prompt.
When it happens
Trigger: The user answered 'no' to the consent prompt; the prompt timed out and defaulted to decline; a non-interactive context where consent could not be obtained.
Common situations: User does not want to grant access to the agent; accidental decline; automation/sandbox where the prompt cannot render; the user cancelled to switch agents.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- OAuth2 authentication for agent "${this.agentName}" requires
- OAuth2 authentication for agent "${this.agentName}" requires
- No access token received from token endpoint
- Execution aborted
- Failed to initialize GCS bucket ${this.bucketName}: ${error}
AI-assisted analysis of google-gemini/gemini-cli@5024443c72 (2026-08-12).
Data as JSON: /api/errors/f8b6a653103ee075.
Report an issue: GitHub.