{"record":{"id":"69f3494bc85923bf","repo":"microsoft/typescript-go","slug":"failed-to-start-cpu-profile-w","errorCode":null,"errorMessage":"failed to start CPU profile: %w","messagePattern":"failed to start CPU profile: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pprof/pprof.go","lineNumber":96,"sourceCode":"\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\n\tc.session = &ProfileSession{\n\t\tcpuFilePath: cpuProfilePath,\n\t\tcpuFile:     cpuFile,\n\t\tlogWriter:   io.Discard,\n\t}\n\treturn nil\n}\n\n// StopCPUProfile stops CPU profiling and returns the path to the profile file.\nfunc (c *CPUProfiler) StopCPUProfile() (string, error) {\n\tc.mu.Lock()\n\tdefer c.mu.Unlock()\n\n\tif c.session == nil {\n\t\treturn \"\", errors.New(\"CPU profiling not in progress\")\n\t}","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/pprof/pprof.go#L78-L114","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// ensure no other runtime/pprof consumer is active before starting\n// (net/http/pprof, go test -cpuprofile, embedded libs)\nif otherProfilerActive() {\n\treturn errors.New(\"stop the other CPU profiler first\")\n}","typeGuard":null,"tryCatchPattern":"if err := profiler.StartCPUProfile(dir); err != nil {\n\tif strings.Contains(err.Error(), \"failed to start CPU profile\") {\n\t\t// single-slot runtime conflict: stop the other source, then retry once\n\t\tstopExternalProfilers()\n\t\treturn profiler.StartCPUProfile(dir)\n\t}\n\treturn err\n}","preventionTips":["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"],"tags":["pprof","runtime","single-instance","conflict"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}