juanfont/headscale · error · ErrTestFailed

%w: exit code %d

Error message

%w: exit code %d

What it means

Returned when the test container ran to completion but `go test` inside it exited non-zero. It wraps the `ErrTestFailed` sentinel ('test failed') plus the concrete exit code, so callers can distinguish 'tests actually failed' from infrastructure errors. Exit code 1 means assertion failures; 2 usually means build/setup errors inside the container; 124-style codes can indicate the internal `-timeout` firing.

Source

Thrown at cmd/hi/docker.go:197

		if exitCode == 0 {
			if config.Verbose {
				log.Printf("Test succeeded, cleaning up artifacts to save disk space...")
			}

			cleanErr := cleanupSuccessfulTestArtifacts(logsDir, config.Verbose)

			if cleanErr != nil && config.Verbose {
				log.Printf("Warning: artifact cleanup failed: %v", cleanErr)
			}
		}
	}

	if err != nil {
		return fmt.Errorf("executing test: %w", err)
	}

	if exitCode != 0 {
		return fmt.Errorf("%w: exit code %d", ErrTestFailed, exitCode)
	}

	log.Printf("Test completed successfully!")

	return nil
}

// buildGoTestCommand constructs the go test command arguments.
func buildGoTestCommand(config *RunConfig) []string {
	cmd := []string{"go", "test", "./..."}

	if config.TestPattern != "" {
		cmd = append(cmd, "-run", config.TestPattern)
	}

	if config.FailFast {
		cmd = append(cmd, "-failfast")
	}

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Scroll the streamed `go test -v` output above the error — the failing test names and assertion diffs are there.
  2. Inspect `control_logs/<runID>/` for hs-*.stderr.log; per repo docs, flakes are almost always code, not Docker.
  3. If it timed out, raise config.Timeout and re-run to see if it's load-related.
  4. Reproduce a single test: `go run ./cmd/hi run "TestName"`.
  5. Try `--postgres` if the failure only appears on one DB backend.
Defensive patterns

Strategy: try-catch

Try / catch

if err := runDockerTest(ctx, config); err != nil {
    if errors.Is(err, ErrTestFailed) {
        // real test failure: read streamed go test -v output and
        // control_logs/<runID>/hs-*.stderr.log; do NOT retry blindly
    }
}

Prevention

When it happens

Trigger: Any failing assertion or panic in the integration suite; compilation failure of the test binary inside the golang container; `go test -timeout` (config.Timeout) exceeded, which produces a panic dump in the streamed output; Docker exit codes from the container propagate as status.StatusCode.

Common situations: Genuine test regressions in hscontrol/mapper/policy; suite timing out on loaded CI machines; environment-dependent tests failing only under Docker (DNS, MTU, address-family differences).

Related errors


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