netbirdio/netbird · warning
service is not up
Error message
service is not up
What it means
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.
Source
Thrown at client/server/server.go:62
retryInitialIntervalVar = "NB_CONN_RETRY_INTERVAL_TIME"
maxRetryIntervalVar = "NB_CONN_MAX_RETRY_INTERVAL_TIME"
maxRetryTimeVar = "NB_CONN_MAX_RETRY_TIME_TIME"
retryMultiplierVar = "NB_CONN_RETRY_MULTIPLIER"
defaultInitialRetryTime = 30 * time.Minute
defaultMaxRetryInterval = 60 * time.Minute
defaultMaxRetryTime = 14 * 24 * time.Hour
defaultRetryMultiplier = 1.7
// JWT token cache TTL for the client daemon (disabled by default)
defaultJWTCacheTTL = 0
errRestoreResidualState = "failed to restore residual state: %v"
errProfilesDisabled = "profiles are disabled, you cannot use this feature without profiles enabled"
errUpdateSettingsDisabled = "update settings are disabled, you cannot use this feature without update settings enabled"
errNetworksDisabled = "network selection is disabled by the administrator"
)
var ErrServiceNotUp = errors.New("service is not up")
// Server for service control.
type Server struct {
rootCtx context.Context
actCancel context.CancelFunc
logFile string
// uiLogPath is the desktop UI's absolute log path, reported via
// RegisterUILog. Guarded by mutex. Consumed by DebugBundle so the bundle
// can collect the GUI log even though the daemon runs as root and can't
// resolve the user's config dir. Last-writer-wins (one UI per socket).
// DebugBundle opens it on behalf of the bundle requester and refuses a file
// that caller does not own, so a local user cannot read another user's log
// or a root-only file through it.
uiLogPath string
oauthAuthFlow oauthAuthFlowView on GitHub (pinned to 93e97f4bf1)
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).
Example fix
// before: surfacing it as a hard failure
err := server.Down(ctx)
if err != nil {
return err // "service is not up" breaks idempotent scripts
}
// after: idempotent down
if err := server.Down(ctx); err != nil && !errors.Is(err, server.ErrServiceNotUp) {
return err
} Defensive patterns
Strategy: validation
Validate before calling
// Only issue Down when there is something to bring down.
status, err := daemonClient.Status(ctx)
if err != nil {
return err
}
if status.GetStatus() == daemonpb.StatusEnum_DOWN {
return nil // desired state already reached
} Type guard
func isServiceNotUp(err error) bool {
return errors.Is(err, server.ErrServiceNotUp) // in-process Go callers
} Try / catch
if err := server.Down(ctx); err != nil {
if server.IsServiceNotUp(err) {
return nil // already down: idempotent success
}
return err
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- client not initialized
- engine not started
- management client is not initialised
- unable to get daemon status: %v
- rule already exists
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/0fd24ce37940dfe3.
Report an issue: GitHub.