juanfont/headscale · error

starting headscale container: %w\n\nDocker build failed. Las

Error message

starting headscale container: %w\n\nDocker build failed. Last %d lines of output:\n%s

What it means

Diagnostic error emitted when the initial BuildAndRunWithBuildOptions failed AND a retry build (run purely to capture output) also failed (buildErr != nil). It wraps the original container-start error together with the last 100 lines of the diagnostic build output, so the message contains the actual Go/overlay build failure that prevented the image from being created.

Source

Thrown at integration/hsic/hsic.go:565

			log.Printf("Docker build/run failed, attempting to get detailed output...")

			buildOutput, buildErr := dockertestutil.RunDockerBuildForDiagnostics(dockerContextPath, IntegrationTestDockerFileName)

			// Show the last 100 lines of build output to avoid overwhelming the logs
			lines := strings.Split(buildOutput, "\n")

			const maxLines = 100

			startLine := 0
			if len(lines) > maxLines {
				startLine = len(lines) - maxLines
			}

			relevantOutput := strings.Join(lines[startLine:], "\n")

			if buildErr != nil {
				// The diagnostic build also failed - this is the real error
				return nil, fmt.Errorf("starting headscale container: %w\n\nDocker build failed. Last %d lines of output:\n%s", err, maxLines, relevantOutput)
			}

			if buildOutput != "" {
				// Build succeeded on retry but container creation still failed
				return nil, fmt.Errorf("starting headscale container: %w\n\nDocker build succeeded on retry, but container creation failed. Last %d lines of build output:\n%s", err, maxLines, relevantOutput)
			}

			// No output at all - diagnostic build command may have failed
			return nil, fmt.Errorf("starting headscale container: %w\n\nUnable to get diagnostic build output (command may have failed silently)", err)
		}
	}

	log.Printf("Created %s container\n", hsic.hostname)

	hsic.container = container

	// Get the dynamically assigned host port for metrics/pprof
	hsic.hostMetricsPort = container.GetHostPort("9090/tcp")

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Read the appended build output lines — they contain the real compile/build error
  2. Run `make build` locally first; fix any Go compile errors before integration tests
  3. Clear Docker build cache (docker builder prune) if the failure is stale-cache related
  4. Free disk space if the build fails during layer writes
Defensive patterns

Strategy: try-catch

Validate before calling

// Compile locally before integration tests
go build ./... || exit 1

Try / catch

if err := hsic.NewHeadscaleInContainer(...); err != nil && strings.Contains(err.Error(), "Docker build failed") {
    // the appended last-100-lines contain the real compile error; surface them verbatim
    t.Fatalf("image build broken: %v", err)
}

Prevention

When it happens

Trigger: Local (non-CI) HeadscaleInContainer construction without a prebuilt image: the embedded Dockerfile build fails twice — e.g. Go compile error in the current working tree, broken Dockerfile, unreachable base image, or disk exhaustion during build.

Common situations: Running integration tests with a compile-broken working tree (the image builds the current headscale source); base image pull failing; corrupted Docker build cache; insufficient disk space.

Related errors


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