juanfont/headscale · error

writing config: %w

Error message

writing config: %w

What it means

"writing config: %w" at cmd/dev/main.go:121 wraps os.WriteFile(configPath, ..., 0o600) in the cmd/dev bootstrapper. After creating the temp dir, the tool renders the devConfig template (ports, metrics port, tmpDir paths) and writes it to <tmpDir>/config.yaml. Failure here is almost always a filesystem-level error on a directory the tool itself just created, or an interrupted run.

Source

Thrown at cmd/dev/main.go:121

	if err != nil {
		return fmt.Errorf("creating temp dir: %w", err)
	}

	if !*keep {
		defer os.RemoveAll(tmpDir)
	}

	// Write config.
	configPath := filepath.Join(tmpDir, "config.yaml")
	configContent := fmt.Sprintf(
		devConfig,
		*port, *port, metricsPort,
		tmpDir, tmpDir, tmpDir,
	)

	err = os.WriteFile(configPath, []byte(configContent), 0o600)
	if err != nil {
		return fmt.Errorf("writing config: %w", err)
	}

	// Build headscale.
	fmt.Println("Building headscale...")

	hsBin := filepath.Join(tmpDir, "headscale")

	ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
	defer stop()

	build := exec.CommandContext(ctx, "go", "build", "-o", hsBin, "./cmd/headscale")
	build.Stdout = os.Stdout
	build.Stderr = os.Stderr

	err = build.Run()
	if err != nil {
		return fmt.Errorf("building headscale: %w", err)
	}

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Free space on the filesystem holding TMPDIR (check df -h "$TMPDIR") and re-run
  2. Point TMPDIR at a larger, local directory
  3. Re-run the command — transient tmp-reaper interference is cleared by a fresh temp dir
Defensive patterns

Strategy: try-catch

Try / catch

if err := os.WriteFile(configPath, []byte(configContent), 0o600); err != nil {
	if errors.Is(err, syscall.ENOSPC) {
		// free space in TMPDIR and retry once with a fresh temp dir
	}
	return fmt.Errorf("writing config: %w", err)
}

Prevention

When it happens

Trigger: Running cmd/dev when the temp dir was removed between MkdirTemp and WriteFile (e.g. aggressive tmp reaper such as systemd-tmpfiles), the filesystem filled up mid-run (ENOSPC), or the process lacks permission in TMPDIR.

Common situations: Disk full during development; TMPDIR on a tmpfs with a small size limit; parallel dev runs racing with cleanup tooling.

Related errors


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