{"record":{"id":"8ccae491222cef1a","repo":"netbirdio/netbird","slug":"getting-a-request-oauth-flow-info-failed-v","errorCode":null,"errorMessage":"getting a request OAuth flow info failed: %v","messagePattern":"getting a request OAuth flow info failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/android/login.go","lineNumber":220,"sourceCode":"\toAuthFlow, err := authClient.GetOAuthFlow(a.ctx, isAndroidTV)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get OAuth flow: %v\", err)\n\t}\n\n\t// An empty hint is deliberate, not a fallback: a fresh profile leaves the\n\t// choice to the IdP. Switching accounts is done by switching or removing\n\t// profiles, not by logging out — logout keeps the email.\n\tif a.cfgPath != \"\" {\n\t\tif hint := readProfileEmail(a.cfgPath); hint != \"\" {\n\t\t\tif setter, ok := oAuthFlow.(loginHintSetter); ok {\n\t\t\t\tsetter.SetLoginHint(hint)\n\t\t\t}\n\t\t}\n\t}\n\n\tflowInfo, err := oAuthFlow.RequestAuthInfo(context.TODO())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting a request OAuth flow info failed: %v\", err)\n\t}\n\n\tgo urlOpener.Open(flowInfo.VerificationURIComplete, flowInfo.UserCode)\n\n\ttokenInfo, err := oAuthFlow.WaitToken(a.ctx, flowInfo)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"waiting for browser login failed: %v\", err)\n\t}\n\n\treturn &tokenInfo, nil\n}\n","sourceCodeStart":202,"sourceCodeEnd":232,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/android/login.go#L202-L232","documentation":"Thrown after the OAuth flow object exists, when oAuthFlow.RequestAuthInfo fails: the flow asks the IdP for a verification URI and user code (device flow) or prepares the PKCE request. The call uses context.TODO(), so it never cancels and fails only on a real error — an HTTP failure from the IdP, an unreachable IdP, or the IdP rejecting the OAuth client. Wrapped verbatim and surfaced as 'interactive sso login failed: ...' on the listener.","triggerScenarios":"foregroundGetTokenInfo calls RequestAuthInfo(context.TODO()) right after GetOAuthFlow succeeded; the POST to the IdP device-authorization endpoint (or PKCE setup) fails because the network dropped between the management check and the IdP call, the IdP is down, the OAuth client_id is invalid/deleted, or the IdP returns a non-2xx response.","commonSituations":"Management reachable but the IdP blocked or slow from the mobile network, IdP outage or maintenance, OAuth client deleted or expired on the IdP side, Android TV devices with flaky Wi-Fi.","solutions":["Confirm the device can reach the IdP endpoints, not just management","Check the OAuth client on the IdP: client_id still valid, device/PKCE flow allowed for it","Inspect the wrapped HTTP status to distinguish IdP rejection from connectivity","Retry the login; each attempt requests fresh auth info"],"exampleFix":"// before: single attempt, any hiccup fails the flow\nauth.Login(listener, urlOpener, false)\n\n// after: in the ErrListener, retry once on transient RequestAuthInfo failures\nfunc (l *loginListener) OnError(err error) {\n\tif strings.Contains(err.Error(), \"getting a request OAuth flow info failed\") && !l.retried {\n\t\tl.retried = true\n\t\tgo auth.Login(l, urlOpener, false) // fresh auth info is requested each attempt\n\t\treturn\n\t}\n\tl.show(err)\n}","handlingStrategy":"retry","validationCode":"// Before Login, confirm general egress works — the SaveConfigIfSSOSupported probe exercises the management path\n// and surfaces network problems before the IdP call is attempted.","typeGuard":null,"tryCatchPattern":"// In the ErrListener: retry once with backoff when RequestAuthInfo failed transiently\nif strings.Contains(err.Error(), \"getting a request OAuth flow info failed\") && !retried {\n\tretried = true\n\ttime.AfterFunc(2*time.Second, func() { go auth.Login(l, urlOpener, false) })\n\treturn\n}","preventionTips":["Monitor IdP availability from the mobile network, not just management","Keep the OAuth client (client_id, flows) valid on the IdP","Retry with backoff — each attempt requests fresh auth info","Log the wrapped HTTP status to distinguish IdP rejection from connectivity"],"tags":["android","go","oauth","idp","network"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}