docker/cli · error

failed waiting for authentication

Error message

failed waiting for authentication: %w

What it means

Returned by OAuthManager.Login when the goroutine polling for the device token (m.api.WaitForDeviceToken) returns an error instead of a TokenResponse. WaitForDeviceToken loops calling getDeviceToken until the user completes browser auth; any non-nil result (network, decode, or terminal OAuth error like expired_device_code) surfaces here wrapped with %w.

Solutions

  1. Re-run `docker login` and complete the browser prompt promptly.
  2. On headless hosts, copy the printed verification URL into a browser on another machine.
  3. Ensure network/proxy is stable for the whole polling window.
  4. If it persists, inspect the wrapped error (e.g. expired_token) and start a fresh flow.

Example fix

# before (user didn't finish, code expired)
docker login  # -> failed waiting for authentication: expired_token
# after
docker login  # open URL quickly this time
# headless: copy the verification URL to a browser elsewhere
Defensive patterns

Strategy: retry

Validate before calling

// only start device flow when a browser is feasible
if !canOpenBrowser() { return errors.New("use `docker login -u <user>` with a PAT on headless hosts") }

Try / catch

if errors.Is(err, context.Canceled) { /* user canceled; do not retry */ } else { /* retry the device flow */ }

Prevention

When it happens

Trigger: The user never completes browser authentication, the device code expires, the browser never opens (press Enter triggers m.openBrowser), network drops during polling, or the tenant returns a fatal OAuth error.

Common situations: Headless environments with no browser; user closes the browser tab; slow user exceeding device_code TTL; network change mid-login; redirect blocked by popup blocker.

Understand the failure class

Related errors


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

Appendix: source

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

			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)