{"record":{"id":"0fd24ce37940dfe3","repo":"netbirdio/netbird","slug":"service-is-not-up","errorCode":null,"errorMessage":"service is not up","messagePattern":"service is not up","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"client/server/server.go","lineNumber":62,"sourceCode":"\tretryInitialIntervalVar = \"NB_CONN_RETRY_INTERVAL_TIME\"\n\tmaxRetryIntervalVar     = \"NB_CONN_MAX_RETRY_INTERVAL_TIME\"\n\tmaxRetryTimeVar         = \"NB_CONN_MAX_RETRY_TIME_TIME\"\n\tretryMultiplierVar      = \"NB_CONN_RETRY_MULTIPLIER\"\n\tdefaultInitialRetryTime = 30 * time.Minute\n\tdefaultMaxRetryInterval = 60 * time.Minute\n\tdefaultMaxRetryTime     = 14 * 24 * time.Hour\n\tdefaultRetryMultiplier  = 1.7\n\n\t// JWT token cache TTL for the client daemon (disabled by default)\n\tdefaultJWTCacheTTL = 0\n\n\terrRestoreResidualState   = \"failed to restore residual state: %v\"\n\terrProfilesDisabled       = \"profiles are disabled, you cannot use this feature without profiles enabled\"\n\terrUpdateSettingsDisabled = \"update settings are disabled, you cannot use this feature without update settings enabled\"\n\terrNetworksDisabled       = \"network selection is disabled by the administrator\"\n)\n\nvar ErrServiceNotUp = errors.New(\"service is not up\")\n\n// Server for service control.\ntype Server struct {\n\trootCtx   context.Context\n\tactCancel context.CancelFunc\n\n\tlogFile string\n\n\t// uiLogPath is the desktop UI's absolute log path, reported via\n\t// RegisterUILog. Guarded by mutex. Consumed by DebugBundle so the bundle\n\t// can collect the GUI log even though the daemon runs as root and can't\n\t// resolve the user's config dir. Last-writer-wins (one UI per socket).\n\t// DebugBundle opens it on behalf of the bundle requester and refuses a file\n\t// that caller does not own, so a local user cannot read another user's log\n\t// or a root-only file through it.\n\tuiLogPath string\n\n\toauthAuthFlow oauthAuthFlow","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/server/server.go#L44-L80","documentation":"Exported sentinel ErrServiceNotUp (client/server/server.go:62), returned by Server.cleanupConnection when s.actCancel is nil, i.e. the daemon has no active connection context. It signals that a teardown-type operation (Down, Logout) was requested while the service was already down; call sites in server.go explicitly match it with errors.Is to treat this case as benign.","triggerScenarios":"Invoking the Down or Logout RPC when the agent is not connected (never started, already stopped, or login never completed) makes cleanupConnection hit the nil actCancel guard and return this sentinel.","commonSituations":"Calling netbird down twice; UI and CLI both issuing Down; scripting that unconditionally runs down after a failed up; MDM policies issuing down on a freshly installed, never-connected agent.","solutions":["Treat it as a no-op: the desired state (service down) already holds.","Check the daemon status before issuing Down to avoid the call entirely.","If you expected the service to be up, inspect logs for why the connection context was never created (failed login/up)."],"exampleFix":"// before: surfacing it as a hard failure\nerr := server.Down(ctx)\nif err != nil {\n    return err // \"service is not up\" breaks idempotent scripts\n}\n\n// after: idempotent down\nif err := server.Down(ctx); err != nil && !errors.Is(err, server.ErrServiceNotUp) {\n    return err\n}","handlingStrategy":"validation","validationCode":"// Only issue Down when there is something to bring down.\nstatus, err := daemonClient.Status(ctx)\nif err != nil {\n    return err\n}\nif status.GetStatus() == daemonpb.StatusEnum_DOWN {\n    return nil // desired state already reached\n}","typeGuard":"func isServiceNotUp(err error) bool {\n    return errors.Is(err, server.ErrServiceNotUp) // in-process Go callers\n}","tryCatchPattern":"if err := server.Down(ctx); err != nil {\n    if server.IsServiceNotUp(err) {\n        return nil // already down: idempotent success\n    }\n    return err\n}","preventionTips":["Make down/logout flows idempotent by treating ErrServiceNotUp as success.","Match with errors.Is in-process; note the sentinel degrades to a string across gRPC.","In scripts, check status before issuing lifecycle commands to avoid the error entirely."],"tags":["go","netbird","daemon","lifecycle","idempotency"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}