juanfont/headscale · critical

creating headscale container: %w

Error message

creating headscale container: %w

What it means

Returned by Scenario.Headscale when hsic.New fails to build and start the headscale control-server container. It wraps container creation, image pull, config mounting, and container start errors from dockertest.

Source

Thrown at integration/scenario.go:482

// Headscale returns a [ControlServer] instance based on hsic ([hsic.HeadscaleInContainer]).
// If the [Scenario] already has an instance, the pointer to the running container
// will be return, otherwise a new instance will be created.
// TODO(kradalby): make port and headscale configurable, multiple instances support?
func (s *Scenario) Headscale(opts ...hsic.Option) (ControlServer, error) {
	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].

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Build the headscale image first: `make build` followed by the documented docker image build step in integration/README.md
  2. Run `go run ./cmd/hi doctor` to validate the Docker environment before tests
  3. Inspect the wrapped error and `docker logs` of the half-created container for startup failures (bad config, bad option)
  4. Disable/comment custom hsic.Options added by the test to isolate the failing option
Defensive patterns

Strategy: try-catch

Validate before calling

if err := integration.CheckDockerEnvironment(); err != nil { // hi doctor equivalent
    t.Skip("docker environment not ready")
}

Try / catch

headscale, err := scenario.Headscale()
if err != nil {
    // environment-level failure: abort, do not retry blindly
    t.Fatalf("control server unavailable: %v", err)
}

Prevention

When it happens

Trigger: First call to s.Headscale() (or any Scenario helper that transitively needs a control server) when the headscale image cannot be pulled/built, config generation fails, or the container exits during startup.

Common situations: Missing or stale locally built headscale image (hsic.New typically uses a locally built image; run make build / the documented docker build first); insufficient Docker resources; a bad hsic.Option (invalid config values, missing env); port conflicts on the host.

Related errors


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