diff --git a/control/controlclient/client.go b/control/controlclient/client.go index e6fe72eec..011701d6b 100644 --- a/control/controlclient/client.go +++ b/control/controlclient/client.go @@ -79,3 +79,9 @@ type Client interface { // requesting a DNS record be created or updated. SetDNS(context.Context, *tailcfg.SetDNSRequest) error } + +// UserVisibleError is an error that should be shown to users. +type UserVisibleError string + +func (e UserVisibleError) Error() string { return string(e) } +func (e UserVisibleError) UserVisibleError() string { return string(e) } diff --git a/control/controlclient/direct.go b/control/controlclient/direct.go index a81aea27a..67446b03b 100644 --- a/control/controlclient/direct.go +++ b/control/controlclient/direct.go @@ -431,7 +431,7 @@ func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, new resp.NodeKeyExpired, resp.MachineAuthorized, resp.AuthURL != "") if resp.Error != "" { - return false, "", errors.New(resp.Error) + return false, "", UserVisibleError(resp.Error) } if resp.NodeKeyExpired { if regen { diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 3345d000f..712154944 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -452,10 +452,13 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) { // TODO(crawshaw): display in the UI. if errors.Is(st.Err, io.EOF) { b.logf("[v1] Received error: EOF") - } else { - b.logf("Received error: %v", st.Err) - e := st.Err.Error() - b.send(ipn.Notify{ErrMessage: &e}) + return + } + b.logf("Received error: %v", st.Err) + var uerr controlclient.UserVisibleError + if errors.As(st.Err, &uerr) { + s := uerr.UserVisibleError() + b.send(ipn.Notify{ErrMessage: &s}) } return }