tailscale / tailscale/tailscale
Unreachable ControlURL does not result in error
- Dominant language
- Go
- Stars
- 36.5k
- Forks
- 3.2k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 123
Description
### What is the issue?
When using tsnet, setting the ControlURL to a URL that does not exist or is not a tailscale-compatible backplane results in no error. Instead the output indicates that the state is "NeedsLogin" which makes the user believe that there are no issues with the ControlURL.
It seems that at some point the tsnet code must get a timeout or other error on its initial request to the ControlURL. It seems this error should at least make it into the logs, and it should be possible for the code that creates and Starts the tsnet server to "catch" it somehow.
### Steps to reproduce
To reproduce, simply run the [tshello](https://tailscale.com/kb/1521/hello-tsnet) example program from the tsilscale docs with one line modified to specify a non-existent tailscale backplane:
```
// This program demonstrates how to use tsnet as a library.
package main
import (
"crypto/tls"
"flag"
"fmt"
"html"
"log"
"net/http"
"strings"
"tailscale.com/tsnet"
)
var (
addr = flag.String("addr", ":80", "address to listen on")
)
func main() {
flag.Parse()
srv := new(tsnet.Server)
srv.ControlURL = "adfljh.asdflkjsfa" // <-- add this line -------------------------
defer srv.Close()
ln, err := srv.Listen("tcp", *addr)
if err != nil {
log.Fatal(err)
}
defer ln.Close()
lc, err := srv.LocalClient()
if err != nil {
log.Fatal(err)
}
if *addr == ":443" {
ln = tls.NewListener(ln, &tls.Config{
GetCertificate: lc.GetCertificate,
})
}
log.Fatal(http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
who, err := lc.WhoIs(r.Context(), r.RemoteAddr)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
fmt.Fprintf(w, "
Hello, world!
\n")fmt.Fprintf(w, "
You are %s from %s (%s)
",html.EscapeString(who.UserProfile.LoginName),
html.EscapeString(firstLabel(who.Node.ComputedName)),
r.RemoteAddr)
})))
}
func firstLabel(s string) string {
s, _, _ = strings.Cut(s, ".")
return s
}
```
The output:
```
2025/06/05 10:36:14 tsnet running state path /Users/[...]/Library/Application Support/tsnet-tsbadurl/tailscaled.state
2025/06/05 10:36:14 tsnet starting with hostname "tsbadurl", varRoot "/Users/[...]/Library/Application Support/tsnet-tsbadurl"
2025/06/05 10:36:14 LocalBackend state is NeedsLogin; running StartLoginInteractive...
```
It then stops producing any output. I have left it running for several minutes waiting for something to time out but no such luck.
### Are there any recent changes that introduced the issue?
_No response_
### OS
macOS
### OS version
MacOS 13.7.5
### Tailscale version
1.84.1
### Other software
_No response_
### Bug report
BUG-NO-LOGS-NO-SUPPORT-this-node-has-had-its-logging-disabled
Contributor guide
Assessment
This issue has not been assessed yet.