microsoft/typescript-go · warning
CPU profiling already in progress
Error message
CPU profiling already in progress
What it means
Returned by CPUProfiler.StartCPUProfile when a profile session already exists (c.session != nil). The profiler is a single-slot resource guarded by a mutex, so a second concurrent or overlapping start request is rejected rather than queueing. This protects the one-writer semantics of runtime/pprof CPU profiles.
Source
Thrown at internal/pprof/pprof.go:80
fmt.Fprintf(p.logWriter, "Memory profile: %v\n", p.memFilePath)
}
fmt.Fprintf(p.logWriter, "CPU profile: %v\n", p.cpuFilePath)
}
// 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)
}
View on GitHub (pinned to 1bcfa18d79)
Solutions
- Call StopCPUProfile (or the corresponding stop request) before starting again
- Treat this error as an idempotency signal: optionally stop-then-restart in one sequence
- Track profiling state on the caller side so concurrent triggers are serialized
Example fix
// before
if err := profiler.StartCPUProfile(dir); err != nil { return err }
// after
if err := profiler.StartCPUProfile(dir); err != nil {
if strings.Contains(err.Error(), "already in progress") {
_, _ = profiler.StopCPUProfile() // reclaim, then retry once
return profiler.StartCPUProfile(dir)
}
return err
} Defensive patterns
Strategy: validation
Validate before calling
// track state on the caller and only start when idle
if !profilingActive.Swap(true) {
if err := profiler.StartCPUProfile(dir); err != nil {
profilingActive.Store(false)
return err
}
} Try / catch
if err := profiler.StartCPUProfile(dir); err != nil {
if errors.Is(err, errProfilingActive) || strings.Contains(err.Error(), "already in progress") {
_, _ = profiler.StopCPUProfile()
return profiler.StartCPUProfile(dir)
}
return err
} Prevention
- Always pair start with a deferred stop
- Serialize profiling triggers through one coordinator
- Treat 'already in progress' as a state hint, not a hard failure
When it happens
Trigger: Calling the start-CPU-profile API/endpoint twice without an intervening stop; a client reconnect and re-issues the start request believing the old session died; two monitoring tools attached to the same server both starting profiles.
Common situations: Automation scripts that retry the start call on timeout; orphaned session after the stop request was lost; misconfigured dashboards polling a profiling endpoint with start instead of status.
Related errors
- CPU profiling not in progress
- failed to create profile directory: %w
- Connection not established
- api: unexpected response message in sync connection
- %w: dir is required
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/459d9ee1a0f6252a.
Report an issue: GitHub.