docker/cli · info

login canceled

Error message

login canceled

What it means

Returned by LoginDevice (internal/oauth/manager/manager.go:131) when the context passed to the method is canceled during the device-token polling loop. The select statement hits the ctx.Done() branch, indicating the user or calling code aborted the login before tokens were received. This is expected/intentional behavior, not a system failure.

Solutions

  1. Handle this error as a normal cancellation, not a failure — check errors.Is(err, context.Canceled) and exit gracefully.
  2. If the cancellation is unexpected, investigate what is canceling the parent context (timeout too short, signal handling).
  3. Increase the context timeout if the user needs more time to complete browser-based authentication.

Example fix

// before: treating cancellation as a hard error
authCfg, err := mgr.LoginDevice(ctx, os.Stdout)
if err != nil {
    log.Fatalf("login failed: %v", err)
}

// after: distinguish cancellation from real errors
authCfg, err := mgr.LoginDevice(ctx, os.Stdout)
if err != nil {
    if errors.Is(err, context.Canceled) || err.Error() == "login canceled" {
        fmt.Fprintln(os.Stderr, "login canceled by user")
        os.Exit(1)
    }
    log.Fatalf("login failed: %v", err)
}
Defensive patterns

Strategy: try-catch

Try / catch

authCfg, err := mgr.LoginDevice(ctx, w)
if err != nil {
    if errors.Is(err, context.Canceled) || err.Error() == "login canceled" {
        // User-initiated cancellation — exit gracefully, not an error
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: During LoginDevice's blocking select (waiting for tokenResChan, waitForTokenErrChan, or ctx.Done), the context is canceled — user presses Ctrl+C, a parent context deadline expires, or the calling code programmatically cancels the context.

Common situations: User presses Ctrl+C at the 'Waiting for authentication in the browser' prompt, script/CI timeout cancels the context, signal handler triggers context cancellation, or the user simply decides not to complete browser login.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/a5fecd5606a0c6ef. Report an issue: GitHub.

Appendix: source

Thrown at internal/oauth/manager/manager.go:131

		tokenRes, err := m.api.WaitForDeviceToken(ctx, state)
		if err != nil {
			waitForTokenErrChan <- err
			return
		}
		tokenResChan <- tokenRes
	}()

	go func() {
		reader := bufio.NewReader(os.Stdin)
		_, _ = reader.ReadString('\n')
		_ = m.openBrowser(state.VerificationURI)
	}()

	_, _ = fmt.Fprint(w, "\nWaiting for authentication in the browser…\n")
	var tokenRes api.TokenResponse
	select {
	case <-ctx.Done():
		return nil, errors.New("login canceled")
	case err := <-waitForTokenErrChan:
		return nil, fmt.Errorf("failed waiting for authentication: %w", err)
	case tokenRes = <-tokenResChan:
	}

	claims, err := oauth.GetClaims(tokenRes.AccessToken)
	if err != nil {
		return nil, fmt.Errorf("failed to parse token claims: %w", err)
	}

	err = m.storeTokensInStore(tokenRes, claims.Domain.Username)
	if err != nil {
		return nil, fmt.Errorf("failed to store tokens: %w", err)
	}

	pat, err := m.api.GetAutoPAT(ctx, m.audience, tokenRes)
	if err != nil {
		return nil, err

View on GitHub (pinned to 4f84911bfe)