microsoft/typescript-go · error

failed to create profile directory: %w

Error message

failed to create profile directory: %w

What it means

StartCPUProfile wraps a failed os.MkdirAll on the requested profile directory. The directory is created lazily at start time; if any path component cannot be created (permission denied, a component is a file, read-only filesystem, path too long), the wrapped *PathError surfaces here and no profiling session begins.

Source

Thrown at internal/pprof/pprof.go:84

}

// CPUProfiler manages on-demand CPU profiling.
type CPUProfiler struct {
	mu      sync.Mutex
	session *ProfileSession
}

// StartCPUProfile starts CPU profiling, writing to the specified directory when stopped.
func (c *CPUProfiler) StartCPUProfile(profileDir string) error {
	c.mu.Lock()
	defer c.mu.Unlock()

	if c.session != nil {
		return errors.New("CPU profiling already in progress")
	}

	if err := os.MkdirAll(profileDir, 0o755); err != nil {
		return fmt.Errorf("failed to create profile directory: %w", err)
	}

	cpuProfilePath := filepath.Join(profileDir, fmt.Sprintf("%d-%d-cpuprofile.pb.gz", os.Getpid(), time.Now().UnixMilli()))
	cpuFile, err := os.Create(cpuProfilePath)
	if err != nil {
		return fmt.Errorf("failed to create CPU profile file: %w", err)
	}

	if err := pprof.StartCPUProfile(cpuFile); err != nil {
		cpuFile.Close()
		os.Remove(cpuProfilePath)
		return fmt.Errorf("failed to start CPU profile: %w", err)
	}

	c.session = &ProfileSession{
		cpuFilePath: cpuProfilePath,
		cpuFile:     cpuFile,
		logWriter:   io.Discard,

View on GitHub (pinned to 1bcfa18d79)

Solutions

  1. Point profileDir at a known-writable location (e.g. os.TempDir()-based or a mounted volume)
  2. Pre-create the directory in your deployment and grant write access to the server's user
  3. Check for regular-file path components shadowing the intended directory

Example fix

// before
err := profiler.StartCPUProfile("/var/run/prof") // root-owned

// after
err := profiler.StartCPUProfile(filepath.Join(os.TempDir(), "prof"))
Defensive patterns

Strategy: validation

Validate before calling

if err := ensureWritableDir(profileDir); err != nil {
	return err
}

func ensureWritableDir(dir string) error {
	if err := os.MkdirAll(dir, 0o755); err != nil {
		return err // surface before calling StartCPUProfile
	}
	probe := filepath.Join(dir, ".probe")
	return os.WriteFile(probe, nil, 0o644)
}

Try / catch

if err := profiler.StartCPUProfile(dir); err != nil {
	if strings.Contains(err.Error(), "failed to create profile directory") {
		return profiler.StartCPUProfile(filepath.Join(os.TempDir(), "prof")) // fallback location
	}
	return err
}

Prevention

When it happens

Trigger: Passing a profileDir under a read-only mount; a parent path component existing as a regular file; EACCES when the server runs as an unprivileged user against a root-owned directory; extremely long or invalid path strings; disk full on some filesystems.

Common situations: Containers with read-only rootfs and no writable volume mounted; profile dir configured under /var/run without permissions; typos creating unintended nested paths on restricted volumes.

Related errors


AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16). Data as JSON: /api/errors/3ac89e692b9a66ea. Report an issue: GitHub.