netbirdio/netbird · error

failed to get log level: %v

Error message

failed to get log level: %v

What it means

Raised by runForDuration (`netbird debug for <duration>`) when client.GetLogLevel fails after Status already succeeded. The command reads the daemon's current log level so it can force TRACE and later restore the original value. The gRPC status message is surfaced verbatim.

Source

Thrown at client/cmd/debug.go:264

	}
	defer func() {
		if err := conn.Close(); err != nil {
			log.Errorf(errCloseConnection, err)
		}
	}()

	client := proto.NewDaemonServiceClient(conn)

	stat, err := client.Status(cmd.Context(), &proto.StatusRequest{ShouldRunProbes: true})
	if err != nil {
		return fmt.Errorf("failed to get status: %v", status.Convert(err).Message())
	}

	stateWasDown := stat.Status != string(internal.StatusConnected) && stat.Status != string(internal.StatusConnecting)

	initialLogLevel, err := client.GetLogLevel(cmd.Context(), &proto.GetLogLevelRequest{})
	if err != nil {
		return fmt.Errorf("failed to get log level: %v", status.Convert(err).Message())
	}

	if stateWasDown {
		if _, err := client.Up(cmd.Context(), &proto.UpRequest{}); err != nil {
			cmd.PrintErrf("Failed to bring service up: %v\n", status.Convert(err).Message())
		} else {
			cmd.Println("netbird up")
			time.Sleep(time.Second * 10)
		}
	}

	initialLevelTrace := initialLogLevel.GetLevel() >= proto.LogLevel_TRACE
	if !initialLevelTrace {
		_, err = client.SetLogLevel(cmd.Context(), &proto.SetLogLevelRequest{
			Level: proto.LogLevel_TRACE,
		})
		if err != nil {
			return fmt.Errorf("failed to set log level to TRACE: %v", status.Convert(err).Message())

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Compare versions: `netbird version` for the CLI versus the daemon version shown by `netbird status`; upgrade whichever is older so both come from the same release
  2. Restart the netbird service and re-run the debug command
  3. If versions match and it persists, check the daemon log at the timestamp of the failure for the rejected RPC
Defensive patterns

Strategy: try-catch

Validate before calling

# ensure daemon version supports the log-level RPCs before running the command
netbird status | grep -q 'Daemon version' && netbird version  # compare the two; upgrade if the daemon is older

Try / catch

resp, err := client.GetLogLevel(ctx, &proto.GetLogLevelRequest{})
if err != nil {
	switch status.Code(err) {
	case codes.Unimplemented:
		// version skew: daemon predates this RPC; upgrade the service
		return fmt.Errorf("daemon too old for GetLogLevel: upgrade the netbird service: %v", err)
	case codes.Unavailable, codes.Canceled:
		// daemon down or command interrupted; restart and retry once
		return fmt.Errorf("daemon unavailable, restart it and retry: %w", err)
	default:
		return err
	}
}

Prevention

When it happens

Trigger: The daemon binary predates the GetLogLevel RPC and returns Unimplemented; the daemon restarts or shuts down between the Status and GetLogLevel calls; the context is canceled mid-sequence; the daemon is in a half-initialized state where the handler is not yet registered.

Common situations: CLI/daemon version skew after a partial upgrade (new CLI package, old service still running); running a built-from-source CLI against a released daemon; the service being restarted by a supervisor mid-command.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/8881ed6e5ad89764. Report an issue: GitHub.