{"record":{"id":"4a811f1126824702","repo":"microsoft/typescript-go","slug":"w-failed-to-start-cpu-profile-w","errorCode":null,"errorMessage":"%w: failed to start CPU profile: %w","messagePattern":"%w: failed to start CPU profile: %w","errorType":"error_code","errorClass":"ErrClientError","httpStatus":null,"severity":"error","filePath":"internal/api/session.go","lineNumber":874,"sourceCode":"\tcase string(MethodGetReferencesToSymbolInFile):\n\t\treturn s.handleGetReferencesToSymbolInFile(ctx, parsed.(*GetReferencesToSymbolInFileParams))\n\tcase string(MethodGetReferencedSymbolsForNode):\n\t\treturn s.handleGetReferencedSymbolsForNode(ctx, parsed.(*GetReferencedSymbolsForNodeParams))\n\tcase string(MethodGetSignatureUsages):\n\t\treturn s.handleGetSignatureUsages(ctx, parsed.(*GetSignatureUsagesParams))\n\tcase string(MethodGetCompletionsAtPosition):\n\t\treturn s.handleGetCompletionsAtPosition(ctx, parsed.(*GetCompletionsAtPositionParams))\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown method: %s\", method)\n\t}\n}\n\nfunc (s *Session) handleStartCPUProfile(_ context.Context, params *ProfileParams) (any, error) {\n\tif params == nil || params.Dir == \"\" {\n\t\treturn nil, fmt.Errorf(\"%w: dir is required\", ErrClientError)\n\t}\n\tif err := s.cpuProfiler.StartCPUProfile(params.Dir); err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: failed to start CPU profile: %w\", ErrClientError, err)\n\t}\n\treturn nil, nil\n}\n\nfunc (s *Session) handleStopCPUProfile(_ context.Context) (*ProfileResult, error) {\n\tfilePath, err := s.cpuProfiler.StopCPUProfile()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: failed to stop CPU profile: %w\", ErrClientError, err)\n\t}\n\treturn &ProfileResult{File: filePath}, nil\n}\n\nfunc (s *Session) handleSaveHeapProfile(_ context.Context, params *ProfileParams) (*ProfileResult, error) {\n\tif params == nil || params.Dir == \"\" {\n\t\treturn nil, fmt.Errorf(\"%w: dir is required\", ErrClientError)\n\t}\n\tfilePath, err := pprof.SaveHeapProfile(params.Dir)\n\tif err != nil {","sourceCodeStart":856,"sourceCodeEnd":892,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/api/session.go#L856-L892","documentation":"startCPUProfile forwarded the underlying profiler error, wrapped in ErrClientError. The wrapped error comes from the cpuProfiler: most commonly Go's pprof \"CPU profiling already in progress\" when a previous profile was never stopped, or a file-creation failure because dir does not exist or is not writable by the server process.","triggerScenarios":"Calling startCPUProfile twice without an intervening stopCPUProfile; passing a dir that was never created; running the server under a user without write permission to dir; read-only container filesystems.","commonSituations":"Profiler lifecycle managed in separate code paths (start on demand, stop on shutdown) that can double-start; orchestrators mounting output dirs read-only; missing mkdir step in deployment scripts.","solutions":["If a profile may already be running, call stopCPUProfile first (ignore its error) before starting again","Ensure dir exists and is writable by the server process (mkdir -p, check ownership/permissions)","Use an absolute path to avoid surprises from the server's working directory"],"exampleFix":"// before\nstart(dir) // may hit \"already in progress\"\n\n// after\nif _, err := stop(); err != nil { /* no active profile; ignore */ }\nif err := start(dir); err != nil { return err }","handlingStrategy":"try-catch","validationCode":"// Pre-flight: create the dir and prove it is writable by the server user.\nif err := os.MkdirAll(dir, 0o755); err != nil { return err }\nprobe := filepath.Join(dir, \".writeprobe\")\nif err := os.WriteFile(probe, nil, 0o644); err != nil { return err }\nos.Remove(probe)","typeGuard":null,"tryCatchPattern":"if err != nil {\n    msg := err.Error()\n    switch {\n    case strings.Contains(msg, \"already in progress\"):\n        _, _ = session.HandleRequest(ctx, string(api.MethodStopCPUProfile), nil) // reset, then retry once\n    case strings.Contains(msg, \"permission\") || strings.Contains(msg, \"no such file\"):\n        return fmt.Errorf(\"profile dir not writable: %s\", dir)\n    }\n    return err\n}","preventionTips":["Guard start with a client-side 'profiling' flag set on success and cleared on stop","mkdir -p the output directory in deployment before enabling profiling","On start failure, stop any stale profile before retrying"],"tags":["profiling","cpu-profile","filesystem","api"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}