juanfont/headscale · warning

reading container logs: %w

Error message

reading container logs: %w

What it means

Returned by HeadscaleInContainer.ReadLog when the underlying Docker API call to stream the headscale container's stdout/stderr logs fails. It wraps the error from dockertestutil.WriteLog, which executes a log-retrieval request against the Docker daemon. This is a test-harness error, not a headscale server error.

Source

Thrown at integration/hsic/hsic.go:727

		_ = t.pool.Purge(t.pgContainer)
	}

	return stdoutPath, stderrPath, t.pool.Purge(t.container)
}

// WriteLogs writes the current stdout/stderr log of the container to
// the given [io.Writer]s.
func (t *HeadscaleInContainer) WriteLogs(stdout, stderr io.Writer) error {
	return dockertestutil.WriteLog(t.pool, t.container, stdout, stderr)
}

// ReadLog returns the current stdout and stderr logs from the headscale container.
func (t *HeadscaleInContainer) ReadLog() (string, string, error) {
	var stdout, stderr bytes.Buffer

	err := dockertestutil.WriteLog(t.pool, t.container, &stdout, &stderr)
	if err != nil {
		return "", "", fmt.Errorf("reading container logs: %w", err)
	}

	return stdout.String(), stderr.String(), nil
}

// SaveLog saves the current stdout log of the container to a path
// on the host system.
func (t *HeadscaleInContainer) SaveLog(path string) (string, string, error) {
	return dockertestutil.SaveLog(t.pool, t.container, path)
}

func (t *HeadscaleInContainer) SaveMetrics(savePath string) error {
	req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, "http://"+net.JoinHostPort(t.hostname, "9090")+"/metrics", nil)
	if err != nil {
		return fmt.Errorf("creating metrics request: %w", err)
	}

	resp, err := http.DefaultClient.Do(req)

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Check that the container is still running before reading logs (call ReadLog before Shutdown/TearDown)
  2. Run `go run ./cmd/hi doctor` and `go run ./cmd/hi cleanup` to remove stale containers/networks from previous runs
  3. Verify the Docker daemon is responsive (`docker ps`) and that no concurrent integration run is purging shared resources
  4. Treat the error as non-fatal in cleanup paths: log it and continue, since the test verdict rarely depends on log retrieval

Example fix

// before
stdout, stderr, err := headscale.ReadLog()
if err != nil {
    t.Fatalf("failed to read logs: %s", err)
}

// after (log-collection is best-effort during cleanup)
stdout, stderr, err := headscale.ReadLog()
if err != nil {
    t.Logf("could not read container logs: %s", err)
}
Defensive patterns

Strategy: try-catch

Try / catch

stdout, stderr, err := headscale.ReadLog()
if err != nil {
    // log collection is diagnostic only; never fail the test verdict on it
    t.Logf("headscale logs unavailable: %v", err)
    stdout, stderr = "", ""
}

Prevention

When it happens

Trigger: Calling scenario headscale.ReadLog() (typically in test cleanup or failure handlers) when the container has already been purged/stopped, the Docker daemon connection is broken, or the container runtime returned an error streaming logs.

Common situations: Calling ReadLog after TearDown/Shutdown has purged the container; Docker daemon restarted mid-test; test-suite container removed by a concurrent run or `hi cleanup`; dockertest pool timeouts.

Related errors


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