juanfont/headscale · critical

reaching headscale container: %w

Error message

reaching headscale container: %w

What it means

Returned by Scenario.Headscale when the freshly created headscale container starts but never becomes reachable — headscale.WaitForRunning() polls the server's health/ready endpoint and timed out. It means the container exists but headscale inside it is not serving.

Source

Thrown at integration/scenario.go:487

	s.mu.Lock()
	defer s.mu.Unlock()

	if headscale, ok := s.controlServers.Load("headscale"); ok {
		return headscale, nil
	}

	if usePostgresForTest {
		opts = append(opts, hsic.WithPostgres())
	}

	headscale, err := hsic.New(s.pool, s.Networks(), opts...)
	if err != nil {
		return nil, fmt.Errorf("creating headscale container: %w", err)
	}

	err = headscale.WaitForRunning()
	if err != nil {
		return nil, fmt.Errorf("reaching headscale container: %w", err)
	}

	s.controlServers.Store("headscale", headscale)

	return headscale, nil
}

// Pool returns the [dockertest.Pool] for the scenario.
func (s *Scenario) Pool() *dockertest.Pool {
	return s.pool
}

// GetOrCreateUser gets or creates a user in the [Scenario].
func (s *Scenario) GetOrCreateUser(userStr string) *User {
	s.mu.Lock()
	defer s.mu.Unlock()

	if user, ok := s.users[userStr]; ok {

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Dump the container logs right after failure: `docker logs <headscale-container>` — headscale usually logs the fatal config error
  2. If using WithPostgres, verify the database container became healthy before headscale starts
  3. Regenerate certs/keys if the test mounts stale or mismatched TLS material
  4. On slow machines, retry the run once — but if it repeats, treat it as a config/code defect per the repo's flake policy
Defensive patterns

Strategy: retry

Try / catch

headscale, err := scenario.Headscale()
if err != nil {
    // pull container logs immediately — WaitForRunning failures are almost always
    // a startup crash visible in stderr
    t.Fatalf("headscale not ready: %v — check container logs", err)
}

Prevention

When it happens

Trigger: Calling any Scenario helper that triggers s.Headscale() when the headscale process inside the container crashes on startup, listens on a different address, or the health check cannot reach the port (network attachment issues).

Common situations: Broken headscale config mounted into the container (bad TLS certs, invalid noise key, unreachable DB); headscale binary/image version mismatch where the config keys changed; Postgres option enabled but the DB container is not ready; slow CI machine hitting the readiness timeout.

Related errors


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