mastra-ai/mastra · info

Login cancelled

Error message

Login cancelled

What it means

loginGitHubCopilot prompts interactively for an optional GitHub Enterprise URL/domain. If the user aborts the operation (via options.signal) after/while the enterprise-domain prompt is shown, the function throws this sentinel Error to signal a deliberate, user-initiated cancellation rather than a failure. Callers (loginPromise/login) treat it as an expected cancellation path.

Source

Thrown at mastracode/sdk/src/auth/providers/github-copilot.ts:391

 * Login with GitHub Copilot OAuth (device-code flow).
 *
 * Prompts for an optional GitHub Enterprise URL/domain, performs the device-code flow,
 * then exchanges the GitHub OAuth token for a Copilot bearer token.
 */
export async function loginGitHubCopilot(options: {
  onAuth: (url: string, instructions?: string) => void;
  onPrompt: (prompt: { message: string; placeholder?: string; allowEmpty?: boolean }) => Promise<string>;
  onProgress?: (message: string) => void;
  signal?: AbortSignal;
}): Promise<GitHubCopilotCredentials> {
  const input = await options.onPrompt({
    message: 'GitHub Enterprise URL/domain (blank for github.com)',
    placeholder: 'company.ghe.com',
    allowEmpty: true,
  });

  if (options.signal?.aborted) {
    throw new Error('Login cancelled');
  }

  const trimmed = input.trim();
  const enterpriseDomain = normalizeDomain(input);
  if (trimmed && !enterpriseDomain) {
    throw new Error('Invalid GitHub Enterprise URL/domain');
  }
  let pending = await startGitHubCopilotDeviceLogin(enterpriseDomain ?? undefined, { signal: options.signal });
  options.onAuth(pending.url, pending.instructions);

  while (true) {
    if (options.signal?.aborted) {
      throw new Error('Login cancelled');
    }

    // Wait before polling (safety margin over the server interval), clamped to the deadline.
    const remainingMs = Math.max(pending.deadlineAt - Date.now(), 0);
    await abortableSleep(Math.min(copilotNextPollDelayMs(pending), remainingMs), options.signal);

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Re-run login() and complete (or leave blank) the enterprise-domain prompt without aborting
  2. If cancellation was accidental, check any wrappers/scripts that abort the signal (timeouts, Ctrl-C forwarding) during the prompt
  3. Handle this error distinctly in your catch block and treat it as a no-op cancellation, not a failure to report

Example fix

// before
await login('github-copilot').catch(err => { throw err; });
// after
try {
  await login('github-copilot');
} catch (err) {
  if (err instanceof Error && err.message === 'Login cancelled') return; // expected user cancel
  throw err;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Abort only intentionally; check before starting login
if (options.signal?.aborted) {
  return; // skip login entirely instead of entering the prompt flow
}

Type guard

function isLoginCancelled(err: unknown): boolean {
  return err instanceof Error && err.message === 'Login cancelled';
}

Try / catch

try {
  await login('github-copilot', { signal });
} catch (err) {
  if (isLoginCancelled(err)) return; // user-initiated, not a failure
  throw err;
}

Prevention

When it happens

Trigger: Calling login() for the GitHub Copilot provider and aborting the supplied AbortSignal (or pressing Ctrl-C/Escape in the interactive prompt flow) while the 'GitHub Enterprise URL/domain' prompt is pending or immediately after it returns, before device login starts.

Common situations: Users cancel the CLI login flow; a timeout or wrapper script aborts the signal while waiting for stdin input; an embedding app cancels a login promise that is blocked on the interactive prompt.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/15d1c4c48369439e. Report an issue: GitHub.