{"record":{"id":"251c04754b6635d8","repo":"netbirdio/netbird","slug":"login-w","errorCode":null,"errorMessage":"login: %w","messagePattern":"login: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/embed/embed.go","lineNumber":265,"sourceCode":"\n\tctx, cancel := context.WithCancel(internal.CtxInitState(context.Background()))\n\tdefer func() {\n\t\tif c.connect == nil {\n\t\t\tcancel()\n\t\t}\n\t}()\n\n\t// nolint:staticcheck\n\tctx = context.WithValue(ctx, system.DeviceNameCtxKey, c.deviceName)\n\n\tauthClient, err := auth.NewAuth(ctx, c.config.PrivateKey, c.config.ManagementURL, c.config)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"create auth client: %w\", err)\n\t}\n\tdefer authClient.Close()\n\n\tif err, _ := authClient.Login(ctx, c.setupKey, c.jwtToken); err != nil {\n\t\treturn fmt.Errorf(\"login: %w\", err)\n\t}\n\tclient := internal.NewConnectClient(ctx, c.config, c.recorder)\n\tclient.SetSyncResponsePersistence(true)\n\n\t// either startup error (permanent backoff err) or nil err (successful engine up)\n\t// TODO: make after-startup backoff err available\n\trun := make(chan struct{})\n\tclientErr := make(chan error, 1)\n\tgo func() {\n\t\tif err := client.Run(run, \"\"); err != nil {\n\t\t\tclientErr <- err\n\t\t}\n\t}()\n\n\tselect {\n\tcase <-startCtx.Done():\n\t\t// ConnectClient.Stop now cancels its own run context and waits for the\n\t\t// run loop to tear the engine down, so this cancel() is no longer","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/embed/embed.go#L247-L283","documentation":"Returned by Client.Start when authClient.Login fails while authenticating to the management server with the setup key or JWT token chosen in embed.New. The wrapped error is the management login error: rejected/expired/over-quota setup key, invalid JWT, unreachable or misbehaving management server, or TLS handshake failure.","triggerScenarios":"Client.Start after embed.New with a revoked or expired SetupKey, a JWTToken past expiry, a management URL pointing at a server that is down or returns an error, or clock skew breaking token validation.","commonSituations":"Setup keys rotated or deleted in the management dashboard while the embedding app kept the old one; JWTs fetched once and reused after expiry; management server behind a load balancer with a stale cert; running against a self-hosted management that is not yet up when the embedder starts.","solutions":["Read the wrapped error to separate credential rejection (fix the credential) from connectivity (fix network/server).","For setup keys: check status/expiry/usage limits in the management dashboard and generate a new key if needed.","For JWT: fetch a fresh token immediately before Start instead of caching it long-term.","For connectivity: verify the management URL responds (curl) and TLS trusts; retry Start with backoff if the server was temporarily down."],"exampleFix":"// before\nif err := client.Start(ctx); err != nil { log.Fatalf(\"start: %v\", err) }\n\n// after\nif err := client.Start(ctx); err != nil {\n    if strings.Contains(err.Error(), \"login:\") {\n        // credential or management-side problem: refresh token/setup key, then retry\n        token, terr := fetchFreshJWT()\n        if terr == nil {\n            client, _ = embed.New(embed.Options{JWTToken: token, ...})\n            err = client.Start(ctx)\n        }\n    }\n    if err != nil { log.Fatalf(\"start: %v\", err) }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := client.Start(ctx)\nif err != nil && strings.Contains(err.Error(), \"login:\") {\n    // credential rejections are permanent: refresh token/setup key, recreate client, retry once\n    // connectivity errors: backoff and retry Start with the same client recreated","preventionTips":["Fetch JWTs immediately before Start; never cache long-lived tokens.","Use setup keys with adequate expiry and usage headroom.","Distinguish credential vs connectivity in the wrapped error before choosing retry vs re-register."],"tags":["auth","credentials","network","embed"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}