juanfont/headscale · error
%s failed to fetch tailscale status: %w
Error message
%s failed to fetch tailscale status: %w
What it means
A `TailscaleInContainer` client failed to run `tailscale status` inside its container; `errTailscaleStatus(hostname, err)` is the annotated wrapper used by all status-dependent helpers (IPs, FQDN, login state). The wrapped error is the exec failure from dockertest.
Source
Thrown at integration/tsic/tsic.go:80
errTailscalePingFailed = errors.New("ping failed")
errTailscalePingNotDERP = errors.New("ping not via DERP")
errTailscaleNotLoggedIn = errors.New("tailscale not logged in")
errTailscaleWrongPeerCount = errors.New("wrong peer count")
errTailscaleCannotUpWithoutAuthkey = errors.New("cannot up without authkey")
errInvalidClientConfig = errors.New("verifiably invalid client config requested")
errInvalidTailscaleImageFormat = errors.New("invalid HEADSCALE_INTEGRATION_TAILSCALE_IMAGE format, expected repository:tag")
errTailscaleImageRequiredInCI = errors.New("HEADSCALE_INTEGRATION_TAILSCALE_IMAGE must be set in CI for HEAD version")
errContainerNotInitialized = errors.New("container not initialized")
errFQDNNotYetAvailable = errors.New("FQDN not yet available")
errCurlEmptyResponseBody = errors.New("curl returned empty response body")
)
const (
VersionHead = "head"
)
func errTailscaleStatus(hostname string, err error) error {
return fmt.Errorf("%s failed to fetch tailscale status: %w", hostname, err)
}
// TailscaleInContainer is an implementation of TailscaleClient which
// sets up a Tailscale instance inside a container.
type TailscaleInContainer struct {
version string
hostname string
pool *dockertest.Pool
container *dockertest.Resource
network *dockertest.Network
// "cache"
ips []netip.Addr
fqdn string
// optional config
caCerts [][]byteView on GitHub (pinned to 565fd254d0)
Solutions
- Read the wrapped exec error — 'tailscaled not running' vs 'connection refused' points to readiness vs crash.
- Wrap status queries in an Eventually/retry loop rather than calling them once.
- Check the client container logs for a tailscaled startup crash.
- If the binary is missing, rebuild the tailscale image (or set HEADSCALE_INTEGRATION_TAILSCALE_IMAGE).
Example fix
// before
ips, err := client.IPs() // one-shot, races tailscaled startup
// after
var ips []netip.Addr
require.EventuallyWithT(t, func(c *assert.CollectT) {
var err error
ips, err = client.IPs()
assert.NoError(c, err)
}, 30*time.Second, time.Second) Defensive patterns
Strategy: retry
Try / catch
// All status-dependent helpers should sit inside an Eventually.
require.EventuallyWithT(t, func(c *assert.CollectT) {
_, err := client.IPs()
assert.NoError(c, err)
}, 60*time.Second, time.Second) Prevention
- Never call status helpers right after container start; wait for tailscaled.
- Read client container logs when status keeps failing.
- Ensure the tailscale image actually contains the binary before running flows.
When it happens
Trigger: Any helper that shells out to `tailscale status` while tailscaled is not running yet, the binary is missing in the container, the socket is down, or tailscaled exited with an error.
Common situations: Querying a client immediately after container start before tailscaled is up; container image built without tailscale installed; tailscaled crashed due to bad flags; test teardown raced the query.
Related errors
- getting IPs: %w
- reaching DERP server: %w
- no network set, called from: %s
- running pre-built tailscale container %q: %w
- %s could not start tailscale container (version: %s): %w Do
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/3cd9479fa481e465.
Report an issue: GitHub.