gohugoio/hugo · error

failed to create CPU profile: %w

Error message

failed to create CPU profile: %w

What it means

Returned by initCPUProfile when os.Create fails for the path given via the --profile-cpu flag (c.r.cpuprofile). Hugo wraps the underlying OS error so the user sees why the profile output file could not be created.

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 8a468df065)

Solutions

  1. Verify the parent directory of the --profile-cpu path exists and is writable; create it first.
  2. Use a simple writable path like ./cpu.prof.
  3. Check filesystem permissions / read-only mounts in CI or containers.

Example fix

// before
hugo --profile-cpu /nonexistent/dir/cpu.prof
// after
mkdir -p ./profiles && hugo --profile-cpu ./profiles/cpu.prof
Defensive patterns

Strategy: validation

Validate before calling

// verify the profile output path is writable before enabling profiling
f, err := os.Create(profilePath)
if err != nil {
    return fmt.Errorf("cpu profile path not writable: %w", err)
}
f.Close()

Type guard

var pathErr *os.PathError
if errors.As(err, &pathErr) {
    // filesystem-level failure (permissions, missing dir)
}

Try / catch

if err := b.build(); err != nil {
    var pe *os.PathError
    if errors.As(err, &pe) && strings.Contains(err.Error(), "CPU profile") {
        // disable profiling flag or choose another path
    }
    return err
}

Prevention

When it happens

Trigger: Running hugo with --profile-cpu <path> where the path's directory does not exist, is not writable, or the path is a directory; wraps errors like ENOENT, EACCES, EISDIR from os.Create.

Common situations: Passing a profile path in a non-existent output directory, running in a read-only container filesystem, or pointing at a location owned by another user.

Related errors


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/2989d35e3f3f3773.json. Report an issue: GitHub ↗.