k3s-io/k3s · error
failed to run tailscale debug prefs: %v
Error message
failed to run tailscale debug prefs: %v
What it means
GetAdvertisedRoutes runs `tailscale debug prefs` via util.ExecCommand and wraps an exec failure, before unmarshalling AdvertiseRoutes from the prefs JSON. The `debug` subcommands are a less stable CLI surface than the public commands, so failures often track CLI version changes or an absent/broken daemon, mirroring the `status --json` case.
Source
Thrown at pkg/vpn/vpn.go:185
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 list
func GetAdvertisedRoutes() ([]netip.Prefix, error) {
output, err := util.ExecCommand("tailscale", []string{"debug", "prefs"})
if err != nil {
return nil, fmt.Errorf("failed to run tailscale debug prefs: %v", err)
}
logrus.Debugf("Output from tailscale debug prefs: %v", output)
var tailscaleOutput TailscalePrefsOutput
err = json.Unmarshal([]byte(output), &tailscaleOutput)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal tailscale output: %v", err)
}
return tailscaleOutput.AdvertiseRoutes, nil
}
// processCLIArgs separates the extraArgs part from the command.
// Note that tailscale flags of type list are comma separated and don't accept spaces, thus we can use strings.Fields to separate flags
func processCLIArgs(command string) (string, []string) {
subCommands := strings.Split(command, ",extraArgs=")
if len(subCommands) > 1 {View on GitHub (pinned to 6ba341e396)
Solutions
- Verify manually: tailscale debug prefs | jq .AdvertiseRoutes
- Upgrade the tailscale CLI to a version that supports `debug prefs` and restart tailscaled
- Ensure tailscaled is running and the node is operational before querying advertised routes
Defensive patterns
Strategy: validation
Validate before calling
if _, err := exec.LookPath("tailscale"); err != nil {
return fmt.Errorf("tailscale CLI not available")
}
// confirm the debug subcommand exists in this CLI version
if err := exec.Command("tailscale", "debug", "prefs", "--help").Run(); err != nil {
return fmt.Errorf("installed tailscale does not support 'debug prefs': %w", err)
} Try / catch
routes, err := vpn.GetAdvertisedRoutes()
if err != nil {
if strings.Contains(err.Error(), "failed to run tailscale debug prefs") {
// usually missing/old CLI or stopped daemon: check tailscale version and tailscaled
}
return nil, err
} Prevention
- Do not rely on `tailscale debug` subcommands across versions - verify after upgrades
- Keep the tailscale CLI new enough to support `debug prefs` on all VPN nodes
- Check tailscaled health before querying advertised routes
When it happens
Trigger: The tailscale CLI is missing, too old to have `debug prefs`, or exits non-zero because tailscaled is not running or is in a broken state.
Common situations: Version drift between the node's tailscale CLI and what the code expects (debug subcommands change between releases); airgapped hosts with old CLIs; daemon stopped or not yet logged in.
Related errors
- failed to run tailscale status --json: %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/b5b72a1df25d99fa.
Report an issue: GitHub.