microsoft/typescript-go · error
failed to start CPU profile: %w
Error message
failed to start CPU profile: %w
What it means
runtime/pprof.StartCPUProfile refused to begin; the overwhelmingly common cause is its 'CPU profiling already in progress' error because the Go runtime allows exactly one active CPU profile per process. This can fire even though this CPUProfiler has no session — another component in the same process called runtime/pprof directly (e.g. net/http/pprof handler, test flags, an embedded library). The file is closed and removed on failure, so no residue is left.
Source
Thrown at internal/pprof/pprof.go:96
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,
}
return nil
}
// StopCPUProfile stops CPU profiling and returns the path to the profile file.
func (c *CPUProfiler) StopCPUProfile() (string, error) {
c.mu.Lock()
defer c.mu.Unlock()
if c.session == nil {
return "", errors.New("CPU profiling not in progress")
}View on GitHub (pinned to 1bcfa18d79)
Solutions
- Stop the other profiling source first (close the /debug/pprof/profile request, remove -cpuprofile, stop the other library's session)
- Check the wrapped error text: 'CPU profiling already in progress' confirms the single-slot conflict
- Design tooling so only one profiler front-end owns runtime/pprof per process
Defensive patterns
Strategy: validation
Validate before calling
// ensure no other runtime/pprof consumer is active before starting
// (net/http/pprof, go test -cpuprofile, embedded libs)
if otherProfilerActive() {
return errors.New("stop the other CPU profiler first")
} Try / catch
if err := profiler.StartCPUProfile(dir); err != nil {
if strings.Contains(err.Error(), "failed to start CPU profile") {
// single-slot runtime conflict: stop the other source, then retry once
stopExternalProfilers()
return profiler.StartCPUProfile(dir)
}
return err
} Prevention
- Run exactly one CPU profiling front-end per process
- Avoid go test -cpuprofile on binaries that also expose the profiling API
- Close lingering /debug/pprof/profile browser tabs/requests before using the API
When it happens
Trigger: net/http/pprof's /debug/pprof/profile endpoint active and capturing; go test -cpuprofile running the binary; a co-embedded library starting its own profile; leftover profile started through a previous API path not tracked by this struct.
Common situations: Diagnosis tooling stacked on the same process (prometheus + pprof endpoints + this API); CI running binaries under test coverage with profiling flags; duplicated profiling wrappers from merged codebases.
Related errors
- SyncRpcChannel: could not obtain pipe file descriptors.
- CPU profiling already in progress
- failed to create profile directory: %w
- failed to create CPU profile file: %w
- CPU profiling not in progress
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/69f3494bc85923bf.
Report an issue: GitHub.