juanfont/headscale · error

DERPer is not ready: %w

Error message

DERPer is not ready: %w

What it means

Returned inside the pool.Retry closure of DERPServerInContainer.WaitForRunning when the HTTPS probe against the DERPer fails at the transport level (connection refused, TLS handshake incomplete, DNS not resolvable). dockertest retries it with backoff; if the DERPer never comes up, this error surfaces.

Source

Thrown at integration/dsic/dsic.go:351

// GetDERPPort returns the DERP port of the DERPer instance.
func (t *DERPServerInContainer) GetDERPPort() int {
	return t.derpPort
}

// WaitForRunning blocks until the DERPer instance is ready to be used.
func (t *DERPServerInContainer) WaitForRunning() error {
	url := "https://" + net.JoinHostPort(t.GetHostname(), strconv.Itoa(t.GetDERPPort())) + "/"
	log.Printf("waiting for DERPer to be ready at %s", url)

	insecureTransport := http.DefaultTransport.(*http.Transport).Clone()      //nolint
	insecureTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} //nolint
	client := &http.Client{Transport: insecureTransport}

	return t.pool.Retry(func() error {
		resp, err := client.Get(url) //nolint
		if err != nil {
			return fmt.Errorf("DERPer is not ready: %w", err)
		}

		if resp.StatusCode != http.StatusOK {
			return errDERPerStatusCodeNotOk
		}

		return nil
	})
}

// ConnectToNetwork connects the DERPer instance to a network.
func (t *DERPServerInContainer) ConnectToNetwork(network *dockertest.Network) error {
	return t.container.ConnectToNetwork(network)
}

// WriteFile save file inside the container.
func (t *DERPServerInContainer) WriteFile(path string, data []byte) error {
	return integrationutil.WriteFileToContainer(t.pool, t.container, path, data)

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Inspect DERPer container logs to confirm the process started and bound 443
  2. Verify the container is attached to the expected Docker network and DNS resolution works between containers
  3. Increase available resources on the CI host or reduce parallelism so startup fits the retry window
Defensive patterns

Strategy: retry

Try / catch

// WaitForRunning already retries; guard only against terminal timeout
if err := derp.WaitForRunning(); err != nil {
    log, _ := derp.SaveLog("/tmp/control")
    t.Fatalf("derp never became ready; logs at %s: %v", log, err)
}

Prevention

When it happens

Trigger: After starting the DERPer container, probing https://<hostname>:443/ fails repeatedly — server not yet listening, container networking broken, or the DERPer process crashed so the port never opens.

Common situations: DERPer exits due to bad flags or cert problems; Docker network/DNS not propagated so the hostname doesn't resolve; overloaded CI hosts making startup exceed the retry budget.

Related errors


AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15). Data as JSON: /api/errors/d0e32fc8955b2d3d. Report an issue: GitHub.