juanfont/headscale · error

creating temp dir: %w

Error message

creating temp dir: %w

What it means

"creating temp dir: %w" at cmd/dev/main.go:104 wraps the error from os.MkdirTemp("", "headscale-dev-") in headscale's developer bootstrapping tool. The dev command builds a scratch directory for its generated config.yaml and binary before running a local server. Failure means the OS could not create a directory in the default temp location (TMPDIR, typically /tmp).

Source

Thrown at cmd/dev/main.go:104

	}

	http.DefaultClient.Timeout = 2 * time.Second
	http.DefaultClient.CheckRedirect = func(*http.Request, []*http.Request) error {
		return http.ErrUseLastResponse
	}

	err := run()
	if err != nil {
		log.Fatal(err)
	}
}

func run() error {
	metricsPort := *port + 1010 // default 9090

	tmpDir, err := os.MkdirTemp("", "headscale-dev-")
	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)
	}

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Check the wrapped error: ENOSPC means free space in /tmp; EACCES means fix permissions or set TMPDIR to a writable dir
  2. Export TMPDIR=/path/to/writable/dir and re-run `go run ./cmd/dev`
  3. Clean stale headscale-dev-* directories if /tmp is full

Example fix

# before
TMPDIR=/nonexistent go run ./cmd/dev

# after
mkdir -p "$HOME/tmp" && TMPDIR="$HOME/tmp" go run ./cmd/dev
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := os.Stat(os.TempDir()); err != nil {
	return fmt.Errorf("TMPDIR %s unusable: %w", os.TempDir(), err)
}

Try / catch

tmpDir, err := os.MkdirTemp("", "headscale-dev-")
if err != nil {
	// read wrapped cause: EACCES -> set TMPDIR; ENOSPC -> free space
	if errors.Is(err, syscall.ENOSPC) {
		return fmt.Errorf("temp filesystem full: %w", err)
	}
	return fmt.Errorf("creating temp dir: %w", err)
}

Prevention

When it happens

Trigger: Running `go run ./cmd/dev` when TMPDIR is unset to a non-existent/unwritable path, /tmp is full (ENOSPC), or the disk quota for temp files is exhausted; the wrapped error identifies syscall.EACCES, ENOSPC, ENOENT, etc.

Common situations: See trigger scenarios.

Related errors


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