netbirdio/netbird · error
unable to get daemon status: %v
Error message
unable to get daemon status: %v
What it means
After switching profiles locally, the CLI calls daemon Status to decide whether to also call Down (teardown) so the new profile takes effect. This error means that Status RPC failed. Because it fires right after a profile switch, the common cause is the daemon reconnecting or reloading its gRPC listener/configuration as part of the switch, or the daemon having crashed during the reload.
Source
Thrown at client/cmd/login.go:275
return fmt.Errorf("switch profile on daemon: %v", err)
}
if err := pm.SwitchProfile(resolvedID); err != nil {
return fmt.Errorf("switch profile: %v", err)
}
conn, err := DialClientGRPCServer(ctx, daemonAddr)
if err != nil {
log.Errorf("failed to connect to service CLI interface %v", err)
return err
}
defer conn.Close()
client := proto.NewDaemonServiceClient(conn)
status, err := client.Status(ctx, &proto.StatusRequest{})
if err != nil {
return fmt.Errorf("unable to get daemon status: %v", err)
}
if status.Status == string(internal.StatusConnected) {
if _, err := client.Down(ctx, &proto.DownRequest{}); err != nil {
log.Errorf("call service down method: %v", err)
return err
}
}
return nil
}
// switchProfile asks the daemon to switch to the profile identified by
// handle (a name, ID, or unique ID prefix). Returns the resolved profile
// ID so the caller can update the local active-profile state without
// re-resolving the handle.
func switchProfile(ctx context.Context, handle string, username string) (profilemanager.ID, error) {
conn, err := DialClientGRPCServer(ctx, daemonAddr)View on GitHub (pinned to 93e97f4bf1)
Solutions
- Check the daemon is alive and healthy: 'netbird service status', 'systemctl status netbird', and the daemon logs
- Retry the original command; if the daemon finished reloading, Status will now succeed
- If the daemon crashed, investigate its logs (journalctl -u netbird) before retrying
- Confirm final state with 'netbird status' and re-run Down/up if the old profile is still active
Example fix
// before: single shot, fails when the daemon is mid-reload
status, err := client.Status(ctx, &proto.StatusRequest{})
if err != nil {
return fmt.Errorf("unable to get daemon status: %v", err)
}
// after: tolerate a transient reload with a short retry
var status *proto.StatusResponse
for attempt := 0; attempt < 3; attempt++ {
status, err = client.Status(ctx, &proto.StatusRequest{})
if err == nil {
break
}
time.Sleep(500 * time.Duration(att+1) * time.Millisecond)
}
if err != nil {
return fmt.Errorf("unable to get daemon status: %w", err)
} Defensive patterns
Strategy: retry
Validate before calling
// Gate on daemon readiness before the Status call
if _, err := client.Status(ctx, &proto.StatusRequest{}); err != nil {
return fmt.Errorf("daemon not ready before switch: %w", err)
} Try / catch
var status *proto.StatusResponse
err = backoff.Retry(func() error {
var e error
status, e = client.Status(ctx, &proto.StatusRequest{})
return e
}, backoff.WithMaxRetries(backoff.NewExponentialBackOff(), 3))
if err != nil {
return fmt.Errorf("unable to get daemon status: %w", err)
} Prevention
- Expect a short reload window after SwitchProfile; build a retry into callers that chain Status immediately after
- Monitor daemon health (systemctl/journal) when scripting profile switches
- If Status keeps failing, check for a crash-looping daemon before retrying further
When it happens
Trigger: Daemon restarting its internal components after SwitchProfile while the CLI immediately calls Status; daemon crash mid-reload; connection to the unix socket/named pipe dropped; permission change on the socket between calls.
Common situations: Profile switch on a connected peer triggers a config reload that races the Status call; Service upgrade or crash-looping daemon; Stale socket file left by a killed daemon
Related errors
- wait for extend session: %v
- switch profile: %v
- switch profile on daemon: %v
- waiting sso login failed with: %v
- trace failed: %v
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/ff0dbb827ed57a6a.
Report an issue: GitHub.