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
- Rerun the login and complete the browser flow immediately after the code is displayed
- Keep client connectivity stable for the duration of the poll (seconds to a couple of minutes)
- If it persists, check management logs for token-endpoint errors and IdP health
- 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
- Finish browser consent immediately; the user code expiry window is short
- Pass a context with timeout (not context.TODO) when calling WaitToken from code
- Prefer setup-key registration for automated or slow-to-approve environments
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
- interactive sso login failed: %v
- getting a request OAuth flow info failed: %v
- management client is not initialised
- private services cannot enable bearer auth (SSO): NetBird-on
- session_idle_timeout must be positive for L4 services
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/c0230c4704626121.
Report an issue: GitHub.