{"record":{"id":"459d9ee1a0f6252a","repo":"microsoft/typescript-go","slug":"cpu-profiling-already-in-progress","errorCode":null,"errorMessage":"CPU profiling already in progress","messagePattern":"CPU profiling already in progress","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/pprof/pprof.go","lineNumber":80,"sourceCode":"\t\tfmt.Fprintf(p.logWriter, \"Memory profile: %v\\n\", p.memFilePath)\n\t}\n\n\tfmt.Fprintf(p.logWriter, \"CPU profile: %v\\n\", p.cpuFilePath)\n}\n\n// CPUProfiler manages on-demand CPU profiling.\ntype CPUProfiler struct {\n\tmu      sync.Mutex\n\tsession *ProfileSession\n}\n\n// StartCPUProfile starts CPU profiling, writing to the specified directory when stopped.\nfunc (c *CPUProfiler) StartCPUProfile(profileDir string) error {\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\n\tif c.session != nil {\n\t\treturn errors.New(\"CPU profiling already in progress\")\n\t}\n\n\tif err := os.MkdirAll(profileDir, 0o755); err != nil {\n\t\treturn fmt.Errorf(\"failed to create profile directory: %w\", err)\n\t}\n\n\tcpuProfilePath := filepath.Join(profileDir, fmt.Sprintf(\"%d-%d-cpuprofile.pb.gz\", os.Getpid(), time.Now().UnixMilli()))\n\tcpuFile, err := os.Create(cpuProfilePath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create CPU profile file: %w\", err)\n\t}\n\n\tif err := pprof.StartCPUProfile(cpuFile); err != nil {\n\t\tcpuFile.Close()\n\t\tos.Remove(cpuProfilePath)\n\t\treturn fmt.Errorf(\"failed to start CPU profile: %w\", err)\n\t}\n","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/pprof/pprof.go#L62-L98","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nif err := profiler.StartCPUProfile(dir); err != nil { return err }\n\n// after\nif err := profiler.StartCPUProfile(dir); err != nil {\n\tif strings.Contains(err.Error(), \"already in progress\") {\n\t\t_, _ = profiler.StopCPUProfile() // reclaim, then retry once\n\t\treturn profiler.StartCPUProfile(dir)\n\t}\n\treturn err\n}","handlingStrategy":"validation","validationCode":"// track state on the caller and only start when idle\nif !profilingActive.Swap(true) {\n\tif err := profiler.StartCPUProfile(dir); err != nil {\n\t\tprofilingActive.Store(false)\n\t\treturn err\n\t}\n}","typeGuard":null,"tryCatchPattern":"if err := profiler.StartCPUProfile(dir); err != nil {\n\tif errors.Is(err, errProfilingActive) || strings.Contains(err.Error(), \"already in progress\") {\n\t\t_, _ = profiler.StopCPUProfile()\n\t\treturn profiler.StartCPUProfile(dir)\n\t}\n\treturn err\n}","preventionTips":["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"],"tags":["pprof","profiling","concurrency","state"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}