{"record":{"id":"54bc5dd24d2e8099","repo":"netbirdio/netbird","slug":"get-service-status-w","errorCode":null,"errorMessage":"get service status: %w","messagePattern":"get service status: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/cmd/profile.go","lineNumber":293,"sourceCode":"\tdefer conn.Close()\n\n\tdaemonClient := proto.NewDaemonServiceClient(conn)\n\n\tswitchResp, err := daemonClient.SwitchProfile(ctx, &proto.SwitchProfileRequest{\n\t\tProfileName: &handle,\n\t\tUsername:    &currUser.Username,\n\t})\n\tif err != nil {\n\t\treturn wrapAmbiguityError(err, handle)\n\t}\n\n\tif err := profileManager.SwitchProfile(profilemanager.ID(switchResp.Id)); err != nil {\n\t\treturn err\n\t}\n\n\tstatus, err := daemonClient.Status(ctx, &proto.StatusRequest{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"get service status: %w\", err)\n\t}\n\n\tif status.Status == string(internal.StatusConnected) {\n\t\tif _, err := daemonClient.Down(ctx, &proto.DownRequest{}); err != nil {\n\t\t\treturn fmt.Errorf(\"call service down method: %w\", err)\n\t\t}\n\t}\n\n\tid := profilemanager.ID(switchResp.Id)\n\tcmd.Printf(\"Profile switched to: %s\\n\", id.ShortID())\n\treturn nil\n}\n\n// wrapAmbiguityError turns the daemon's gRPC InvalidArgument errors\n// (which carry the resolver's message verbatim) into CLI-friendly text\n// that points the user at --show-id.\nfunc wrapAmbiguityError(err error, handle string) error {\n\tif err == nil {","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/profile.go#L275-L311","documentation":"During `netbird profile select`, after SwitchProfile succeeded, the follow-up daemonClient.Status RPC failed. The whole select flow runs under the 7s context created in selectProfileFunc, so a daemon that is mid-restart (switching profiles can cause reconnection work) or a busy daemon can exceed it. The %w wrap keeps the gRPC status (often DeadlineExceeded or Unavailable).","triggerScenarios":"Daemon busy tearing down/bringing up the connection for the new profile and missing the 7s deadline; daemon restarted during the switch; connection to the daemon socket dropped mid-call; management login for the new profile still in flight.","commonSituations":"Selecting a profile whose management host is slow to contact; low-spec machines where the daemon takes seconds to switch; selecting right after another state-changing command.","solutions":["Retry the select once the daemon settles (`netbird status` to verify)","Check daemon logs for what the switch was doing when Status timed out","Increase daemon responsiveness (upgrade, reduce log verbosity, check CPU contention)","If reproducible, report with logs — the switch itself (SwitchProfile) already succeeded; only the status check failed"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// After a successful SwitchProfile, poll status instead of one 7s-bound call\n// (illustrative wrapper around the CLI flow)\nnetbird status >/dev/null 2>&1 || sleep 2  # let the daemon settle, then check again","typeGuard":null,"tryCatchPattern":"status, err := daemonClient.Status(ctx, &proto.StatusRequest{})\nif err != nil {\n    if errors.Is(ctx.Err(), context.DeadlineExceeded) {\n        // switch itself succeeded; only the status probe timed out\n        return fmt.Errorf(\"profile switched, but status check timed out; verify with `netbird status`\")\n    }\n    return fmt.Errorf(\"get service status: %w\", err)\n}","preventionTips":["Treat a failed status probe after a successful switch as non-fatal — verify with `netbird status`","Give the daemon a moment after profile switches before automating follow-ups","Watch daemon logs when switches consistently time out"],"tags":["grpc","daemon","timeout","profiles"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}