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
- Free disk space (prune control_logs/) and re-run — partial artifacts without the stderr log make diagnosis hard
- Check permissions on control_logs/<runID>/
- 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
- Reserve disk headroom for both log files before extraction
- hs-*.stderr.log is the primary debugging artifact — never drop it silently on write failure
- Monitor control_logs/ growth in long-lived CI workers
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
- writing stdout log: %w
- getting absolute path for logs directory: %w
- creating logs directory: %w
- extracting logs: %w
- reading map responses from directory: %w
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/2d8fd85a6551d7dc.
Report an issue: GitHub.