netbirdio/netbird · error

waiting for browser login failed: %v

Error message

waiting for browser login failed: %v

What it means

oAuthFlow.WaitToken failed while polling for the browser login to complete. This wraps the terminal outcomes of the RFC 8628 token poll: the device/user code expired before approval, authorization was denied/pending past the deadline, a 'slow_down' exhaustion, a transport error to the token endpoint, or context cancellation. Note the source uses context.TODO(), so daemon/management-side deadlines and code expiry dominate rather than CLI-side cancellation.

Source

Thrown at client/cmd/login.go:425

	} else if profileState.Email != "" {
		hint = profileState.Email
	}

	oAuthFlow, err := auth.NewOAuthFlow(ctx, config, util.HasGraphicalSession(), false, hint)
	if err != nil {
		return nil, err
	}

	flowInfo, err := oAuthFlow.RequestAuthInfo(context.TODO())
	if err != nil {
		return nil, fmt.Errorf("getting a request OAuth flow info failed: %v", err)
	}

	openURL(cmd, flowInfo.VerificationURIComplete, flowInfo.UserCode, noBrowser, showQR)

	tokenInfo, err := oAuthFlow.WaitToken(context.TODO(), flowInfo)
	if err != nil {
		return nil, fmt.Errorf("waiting for browser login failed: %v", err)
	}

	return &tokenInfo, nil
}

func openURL(cmd *cobra.Command, verificationURIComplete, userCode string, noBrowser, showQR bool) {
	var codeMsg string
	if userCode != "" && !strings.Contains(verificationURIComplete, userCode) {
		codeMsg = fmt.Sprintf("and enter the code %s to authenticate.", userCode)
	}

	if noBrowser {
		cmd.Println("Use this URL to log in:\n\n" + verificationURIComplete + " " + codeMsg)
	} else {
		cmd.Println("Please do the SSO login in your browser. \n" +
			"If your browser didn't open automatically, use this URL to log in:\n\n" +
			verificationURIComplete + " " + codeMsg)
	}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Rerun the login and complete the browser flow immediately after the code is displayed
  2. Keep client connectivity stable for the duration of the poll (seconds to a couple of minutes)
  3. If it persists, check management logs for token-endpoint errors and IdP health
  4. For automation or headless hosts, prefer setup-key login instead of the browser device flow
Defensive patterns

Strategy: try-catch

Validate before calling

// Bound the wait with a real context sized to the code lifetime instead of TODO
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
tokenInfo, err := oAuthFlow.WaitToken(ctx, flowInfo)

Try / catch

tokenInfo, err := oAuthFlow.WaitToken(ctx, flowInfo)
if err != nil {
    if ctx.Err() != nil {
        return fmt.Errorf("browser login timed out/canceled: %w", err)
    }
    return fmt.Errorf("waiting for browser login failed: %w", err)
}

Prevention

When it happens

Trigger: User opens the verification URI but never finishes consent before the code expires; user denies consent; network drop to management mid-poll; management restart during the poll; token endpoint returning errors repeatedly.

Common situations: Browser tab left open on the code page without completing login; IdP MFA prompts delayed or failing; Unstable Wi-Fi/VPN dropping the polling connection; Management redeployed mid-login

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/c0230c4704626121. Report an issue: GitHub.