juanfont/headscale · error

writing stderr log: %w

Error message

writing stderr log: %w

What it means

os.WriteFile failed while writing the demultiplexed stderr log to <logsDir>/<containerName>.stderr.log. Identical failure class to the stdout write: missing directory, permission denied, or disk full. Note this happens after the stdout file was already written, so a disk-full failure here means you got a partial artifact set.

Source

Thrown at cmd/hi/docker.go:810

	stderrPath := filepath.Join(logsDir, containerName+".stderr.log")

	// Create buffers to capture stdout and stderr separately
	var stdoutBuf, stderrBuf bytes.Buffer

	// Demultiplex the Docker logs stream to separate stdout and stderr
	_, err = stdcopy.StdCopy(&stdoutBuf, &stderrBuf, logReader)
	if err != nil {
		return fmt.Errorf("demultiplexing container logs: %w", err)
	}

	// Write stdout logs
	if err := os.WriteFile(stdoutPath, stdoutBuf.Bytes(), 0o644); err != nil { //nolint:gosec,noinlineerr // log files should be readable
		return fmt.Errorf("writing stdout log: %w", err)
	}

	// Write stderr logs
	if err := os.WriteFile(stderrPath, stderrBuf.Bytes(), 0o644); err != nil { //nolint:gosec,noinlineerr // log files should be readable
		return fmt.Errorf("writing stderr log: %w", err)
	}

	if verbose {
		log.Printf("Saved logs for %s: %s, %s", containerName, stdoutPath, stderrPath)
	}

	return nil
}

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Free disk space (prune control_logs/) and re-run — partial artifacts without the stderr log make diagnosis hard
  2. Check permissions on control_logs/<runID>/
  3. If stderr is huge because a container is crash-looping, inspect `docker logs <container>` directly to find the underlying test failure
Defensive patterns

Strategy: validation

Validate before calling

// Same directory-writability probe as the stdout write; run once before extraction
if err := os.MkdirAll(logsDir, 0o755); err != nil { return err }
if free := diskFree(logsDir); free < 250*1024*1024 { // runs produce ~100 MB
    return fmt.Errorf("insufficient disk space: %d bytes free", free)
}

Try / catch

if err := os.WriteFile(stderrPath, stderrBuf.Bytes(), 0o644); err != nil {
    if errors.Is(err, syscall.ENOSPC) {
        // stderr is the most valuable artifact (hs-*.stderr.log); try a tmpfs fallback
        _ = os.WriteFile(filepath.Join(os.TempDir(), containerName+".stderr.log"), stderrBuf.Bytes(), 0o644)
    }
    return fmt.Errorf("writing stderr log: %w", err)
}

Prevention

When it happens

Trigger: os.WriteFile(stderrPath, ...) failing with EACCES, ENOSPC, or ENOENT after stdoutPath was written successfully — typically the last write that exhausts remaining disk space.

Common situations: Disk exactly filling up between the stdout and stderr writes; directory permissions changed mid-run; stderr output being much larger than stdout (hs-*.stderr.log is where headscale diagnostics go, and AGENTS.md says to read hs-*.stderr.log first when diagnosing flakes).

Related errors


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