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
- Read the appended build output lines — they contain the real compile/build error
- Run `make build` locally first; fix any Go compile errors before integration tests
- Clear Docker build cache (docker builder prune) if the failure is stale-cache related
- 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
- Run `make build` before integration tests so compile errors surface cheaply
- Read the appended build output — it pinpoints the failing source line
- Prune Docker build cache when failures look stale
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
- starting headscale container: %w\n\nUnable to get diagnostic
- dumping config: %w
- creating certificates for derp test: %w
- %s starting tailscale DERPer container (version: %s): %w
- writing TLS certificate to container: %w
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/b0edb4e3542f1503.
Report an issue: GitHub.