gohugoio/hugo · error

failed to create CPU profile

Error message

failed to create CPU profile: %w

What it means

Hugo's `hugoBuilder.initCPUProfile` calls `os.Create(c.r.cpuprofile)` to open the output file for a Go CPU profile (set via `--cpuprofile`). This error wraps the OS-level file creation failure. It fires before any profiling starts, so the process has not yet begun capturing samples.

Solutions

  1. Verify the parent directory exists and is writable, then re-run `hugo --cpuprofile=<abs/path/cpu.prof>`.
  2. Use an absolute path under a directory you own (e.g. `~/cpu.prof`) instead of a bare filename.
  3. Drop `--cpuprofile` entirely if you do not need profiling — `initCPUProfile` is a no-op when the flag is empty.

Example fix

// before
// $ hugo --cpuprofile=/var/run/cpu.prof
// after
// $ mkdir -p /tmp/hugoprof && hugo --cpuprofile=/tmp/hugoprof/cpu.prof
Defensive patterns

Strategy: validation

Validate before calling

// Validate writability before launching Hugo with --cpuprofile.
import (
  "os"
  "path/filepath"
)
func validateProfilePath(p string) error {
  dir := filepath.Dir(p)
  info, err := os.Stat(dir)
  if err != nil { return err }
  if !info.IsDir() { return os.ErrNotExist }
  // probe writability
  f, err := os.CreateTemp(dir, ".hugocpu-*")
  if err != nil { return err }
  f.Close(); os.Remove(f.Name())
  return nil
}

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: Invoked when `c.r.cpuprofile != ""` (the `--cpuprofile` flag was passed) and `os.Create` returns a non-nil error — e.g. a directory in the path does not exist, the path is read-only, or the user lacks write permission.

Common situations: Passing a relative `--cpuprofile=cpu.prof` from a working directory that is not writable; pointing the flag at an unwritable or non-existent directory like `/var/log/cpu.prof`; a typo in the path including a missing parent directory.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/2989d35e3f3f3773. Report an issue: GitHub.

Appendix: source

Thrown at commands/hugobuilder.go:179

// getDirList provides NewWatcher() with a list of directories to watch for changes.
func (c *hugoBuilder) getDirList() ([]string, error) {
	h, err := c.hugo()
	if err != nil {
		return nil, err
	}

	return hstrings.UniqueStringsSorted(h.PathSpec.BaseFs.WatchFilenames()), nil
}

func (c *hugoBuilder) initCPUProfile() (func(), error) {
	if c.r.cpuprofile == "" {
		return nil, nil
	}

	f, err := os.Create(c.r.cpuprofile)
	if err != nil {
		return nil, fmt.Errorf("failed to create CPU profile: %w", err)
	}
	if err := pprof.StartCPUProfile(f); err != nil {
		f.Close()
		return nil, fmt.Errorf("failed to start CPU profile: %w", err)
	}
	return func() {
		pprof.StopCPUProfile()
		f.Close()
	}, nil
}

func (c *hugoBuilder) initMemProfile() {
	if c.r.memprofile == "" {
		return
	}

	f, err := os.Create(c.r.memprofile)
	if err != nil {

View on GitHub (pinned to 52c9bd7908)