microsoft/typescript-go · warning
CPU profiling not in progress
Error message
CPU profiling not in progress
What it means
StopCPUProfile found c.session == nil, meaning no CPU profile was started through this CPUProfiler. There is nothing to flush and no path to return, so the stop request is rejected instead of silently succeeding. This mirrors the start/stop pairing contract of the profiling API.
Source
Thrown at internal/pprof/pprof.go:113
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")
}
filePath := c.session.cpuFilePath
c.session.Stop()
c.session = nil
return filePath, nil
}
// SaveHeapProfile saves a heap profile to the specified directory.
func SaveHeapProfile(profileDir string) (string, error) {
if err := os.MkdirAll(profileDir, 0o755); err != nil {
return "", fmt.Errorf("failed to create profile directory: %w", err)
}
heapProfilePath := filepath.Join(profileDir, fmt.Sprintf("%d-%d-heapprofile.pb.gz", os.Getpid(), time.Now().UnixMilli()))
heapFile, err := os.Create(heapProfilePath)
if err != nil {View on GitHub (pinned to 1bcfa18d79)
Solutions
- Treat this error as benign if the goal is 'ensure stopped' — the state you wanted is already reached
- Track profiling state client-side and only send stop after a confirmed start
- Make teardown idempotent by ignoring this specific message
Example fix
// before
path, err := profiler.StopCPUProfile()
if err != nil { log.Fatal(err) }
// after
path, err := profiler.StopCPUProfile()
if err != nil && err.Error() != "CPU profiling not in progress" {
return err // real failure
} Defensive patterns
Strategy: validation
Validate before calling
// client-side state flag eliminates the mismatch
if !profiling {
return "", nil // nothing to stop; desired state already holds
}
path, err := profiler.StopCPUProfile()
profiling = false Try / catch
path, err := profiler.StopCPUProfile()
if err != nil {
if err.Error() == "CPU profiling not in progress" {
return "", nil // idempotent stop: already stopped
}
return "", err
} Prevention
- Track start/stop state on the caller side
- Make shutdown paths idempotent and tolerate the not-in-progress error
- Do not blind-retry stop requests after timeouts without checking state
When it happens
Trigger: Calling stop twice (first stop already nilled the session); calling stop after a failed start; stop racing a start that never happened because the client lost track of state; stop issued after the runtime profile was started by a different component not tracked here.
Common situations: Client retry logic duplicating the stop request after a timeout; UI showing a 'profiling' state that desynced from the server after an error; scripts that unconditionally stop at exit.
Related errors
- CPU profiling already in progress
- failed to create profile directory: %w
- %w: dir is required
- %w: failed to start CPU profile: %w
- %w: failed to stop CPU profile: %w
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/f925f51c0c36a899.
Report an issue: GitHub.