k3s-io/k3s · error
failed to run tailscale status --json: %v
Error message
failed to run tailscale status --json: %v
What it means
getTailscaleInfo shells out to `tailscale status --json` via util.ExecCommand; a failure of that exec (binary not found on PATH, or the command exiting non-zero) is wrapped here. It is called by GetInfo and by StartVPN to decide whether tailscale is already in the Running state.
Source
Thrown at pkg/vpn/vpn.go:163
if authInfo.JoinKey == "" {
return errors.New("VPN Error. Tailscale requires a JoinKey")
}
if authInfo.ControlServerURL != "" {
if _, err := url.Parse(authInfo.ControlServerURL); err != nil {
return fmt.Errorf("VPN Error. Invalid control server URL for Tailscale: %w", err)
}
}
return nil
}
return errors.New("Requested VPN: " + authInfo.Name + " is not supported. We currently only support tailscale")
}
// getTailscaleInfo returns the IPs of the interface
func getTailscaleInfo() (*Info, error) {
output, err := util.ExecCommand("tailscale", []string{"status", "--json"})
if err != nil {
return nil, fmt.Errorf("failed to run tailscale status --json: %v", err)
}
logrus.Debugf("Output from tailscale status --json: %v", output)
var tailscaleOutput TailscaleOutput
err = json.Unmarshal([]byte(output), &tailscaleOutput)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal tailscale output: %v", err)
}
// Errors are ignored because the interface might not have ipv4 or ipv6 addresses (that's the only possible error)
ipv4Address, _ := util.GetFirst4String(tailscaleOutput.TailscaleIPs)
ipv6Address, _ := util.GetFirst6String(tailscaleOutput.TailscaleIPs)
return &Info{BackendState: tailscaleOutput.BackendState, IPv4Address: net.ParseIP(ipv4Address), IPv6Address: net.ParseIP(ipv6Address), NodeID: "", ProviderName: "tailscale", Interface: tailscaleIf}, nil
}
// get Tailscale advertised route listView on GitHub (pinned to 6ba341e396)
Solutions
- Check the CLI: command -v tailscale && tailscale version
- Check the daemon: systemctl status tailscaled, then start/enable it
- Run tailscale status manually to see the real failure and fix it (login state, permissions, socket path)
- If the binary must exist inside a container, ensure the image installs it and PATH includes it
Defensive patterns
Strategy: validation
Validate before calling
if _, err := exec.LookPath("tailscale"); err != nil {
return fmt.Errorf("tailscale CLI not installed or not on PATH")
}
// optional: confirm the daemon answers before starting
if out, err := exec.Command("tailscale", "status").CombinedOutput(); err != nil {
return fmt.Errorf("tailscale not operational: %v (%s)", err, out)
} Try / catch
info, err := vpn.GetInfo(vpnAuth)
if err != nil {
if strings.Contains(err.Error(), "failed to run tailscale status --json") {
// check: command -v tailscale; systemctl status tailscaled
}
return nil, err
} Prevention
- Install the tailscale CLI in the image/host before enabling the VPN integration
- Ensure tailscaled is enabled and running before the agent starts the VPN
- Smoke-test `tailscale status` manually once per host to catch login/state issues
- Keep tailscale CLI and daemon versions in sync
When it happens
Trigger: The tailscale CLI is not installed or not on PATH; tailscaled is not running so `tailscale status` exits non-zero; tailscale is in a broken or logged-out state that makes the command fail.
Common situations: Host or container image without the tailscale CLI installed; tailscaled systemd unit not started; agent container lacking the binary while its config requests the VPN; partial upgrades leaving a broken CLI.
Related errors
- failed to run tailscale debug prefs: %v
- Requested VPN: %s is not supported. We currently only suppor
- VPN Error. The passed VPN auth info includes an unknown para
- VPN Error. Invalid control server URL for Tailscale: %w
- failed to unmarshal tailscale output: %v
AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15).
Data as JSON: /api/errors/5e6d3d84551542bf.
Report an issue: GitHub.