{"record":{"id":"57e8ec9c41b5838c","repo":"netbirdio/netbird","slug":"failed-to-create-auth-client-v-57e8ec","errorCode":null,"errorMessage":"failed to create auth client: %v","messagePattern":"failed to create auth client: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/android/session.go","lineNumber":292,"sourceCode":"\tif c.extendCancel != nil {\n\t\tc.extendCancel()\n\t\tc.extendCancel = nil\n\t}\n}\n\nfunc (c *Client) extendAuthSession(ctx context.Context, urlOpener URLOpener, isAndroidTV bool) error {\n\tcfg, cfgPath, cc := c.authSnapshot()\n\tif cfg == nil || cc == nil {\n\t\treturn fmt.Errorf(\"engine is not running\")\n\t}\n\tengine := cc.Engine()\n\tif engine == nil {\n\t\treturn fmt.Errorf(\"engine is not initialized\")\n\t}\n\n\tauthClient, err := auth.NewAuth(ctx, cfg.PrivateKey, cfg.ManagementURL, cfg)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create auth client: %v\", err)\n\t}\n\tdefer authClient.Close()\n\n\t// Passing the config path makes the flow pick up the login_hint: an extend\n\t// renews the session of the account already signed in, so it must not stop to\n\t// offer a choice.\n\ta := NewAuthWithConfig(ctx, cfg, cfgPath)\n\ttokenInfo, err := a.foregroundGetTokenInfo(authClient, urlOpener, isAndroidTV)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"interactive sso login failed: %v\", err)\n\t}\n\n\tif _, err := engine.ExtendAuthSession(ctx, tokenInfo.GetTokenToUse()); err != nil {\n\t\treturn err\n\t}\n\tc.clearLoginRequired()\n\n\tgo urlOpener.OnLoginSuccess()","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/android/session.go#L274-L310","documentation":"extendAuthSession calls auth.NewAuth to build the management gRPC client used for the SSO token exchange, and this wraps its failure. NewAuth fails in two places: parsing the WireGuard private key from the stored config (wgtypes.ParseKey), or dialing the management service (mgm.NewClient) with the configured URL and TLS scheme. The error therefore means either the stored identity is corrupt or management is not reachable.","triggerScenarios":"cfg.PrivateKey in the profile store is empty, truncated, or not a valid base64 WireGuard key (66 chars, base64-encoded); cfg.ManagementURL unreachable: DNS failure, management server down, firewall blocking the port, self-signed cert on an https:// URL without the configured trust; proxy or captive portal intercepting the connection on Android.","commonSituations":"Corrupted config after an app update or incomplete migration of the profile store; management hostname changed or on-prem management stopped; device offline (airplane mode, network switch) when the expiry warning triggered an extend; TLS certificate rotated and the Android system trust store rejects it.","solutions":["Verify the device can reach the configured management URL (curl https://<mgmt-host> from the device network; check DNS and port)","Inspect the stored profile: the management URL must be valid and the private key present — if the store is corrupt, log out and re-login (re-register the client) to regenerate it","If TLS is the cause (cert verify errors in log), renew/install the management certificate and ensure the Android trust store accepts it","Retry once the network is back — a transient dial failure surfaces through this same error"],"exampleFix":"// before: failing on corrupt key silently stored after a partial write\nauthClient, err := auth.NewAuth(ctx, cfg.PrivateKey, cfg.ManagementURL, cfg)\n\n// after: fail fast with an actionable distinction between key and dial errors\nif _, keyErr := wgtypes.ParseKey(cfg.PrivateKey); keyErr != nil {\n    return fmt.Errorf(\"stored private key is invalid, re-register the client: %v\", keyErr)\n}\nauthClient, err := auth.NewAuth(ctx, cfg.PrivateKey, cfg.ManagementURL, cfg)","handlingStrategy":"retry","validationCode":"// Before extend, verify the key parses and management answers:\nif _, err := wgtypes.ParseKey(cfg.PrivateKey); err != nil {\n    return fmt.Errorf(\"re-register needed: %v\", err)\n}\nif _, err := net.DialTimeout(\"tcp\", cfg.ManagementURL.Host, 3*time.Second); err != nil {\n    return fmt.Errorf(\"management unreachable: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"// Retry once after connectivity returns; surface persistent key errors as re-register:\nclient, err := auth.NewAuth(ctx, key, url, cfg)\nif err != nil {\n    if !isTransient(err) { // key parse errors are permanent\n        return permanentErr(err)\n    }\n    time.Sleep(backoff)\n    client, err = auth.NewAuth(ctx, key, url, cfg)\n    if err != nil { return err }\n}","preventionTips":["Treat a key-parse failure at this point as data corruption requiring re-login, never retry it","Check airplane mode/onConnect state before triggering session extend from background workers","Keep the management URL validated at login time so a corrupt URL cannot persist into the store"],"tags":["android","auth","management","network","tls","mobile"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}