golangci/golangci-lint · error

can't start CPU profiling: %w

Error message

can't start CPU profiling: %w

What it means

golangci-lint wraps the error returned by runtime/pprof's StartCPUProfile when the user requested CPU profiling via --cpu-profile. StartCPUProfile fails only if a CPU profile is already active in the process. The wrap preserves the underlying pprof error so the CLI can exit with a clear message.

Source

Thrown at pkg/commands/run.go:271

			if exitErr, ok := errors.AsType[*exitcodes.ExitError](err); ok {
				c.exitCode = exitErr.Code
			} else {
				c.exitCode = exitcodes.Failure
			}
		}
	}

	c.setupExitCode(ctx)
}

func (c *runCommand) startTracing() error {
	if c.opts.CPUProfilePath != "" {
		f, err := os.Create(c.opts.CPUProfilePath)
		if err != nil {
			return fmt.Errorf("can't create file %s: %w", c.opts.CPUProfilePath, err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			return fmt.Errorf("can't start CPU profiling: %w", err)
		}
	}

	if c.opts.MemProfilePath != "" {
		if rate := os.Getenv(envMemProfileRate); rate != "" {
			runtime.MemProfileRate, _ = strconv.Atoi(rate)
		}
	}

	if c.opts.TracePath != "" {
		f, err := os.Create(c.opts.TracePath)
		if err != nil {
			return fmt.Errorf("can't create file %s: %w", c.opts.TracePath, err)
		}
		if err = trace.Start(f); err != nil {
			return fmt.Errorf("can't start tracing: %w", err)
		}
	}

View on GitHub (pinned to ed7a235d2d)

Solutions

  1. Remove the pre-existing pprof.StartCPUProfile call (or stop it with pprof.StopCPUProfile) before running golangci-lint with --cpu-profile.
  2. Run golangci-lint as a separate process instead of embedding it in a program that already profiles itself.
  3. Drop --cpu-profile if profiling is not needed; use a different output path only when the conflict is with another run's profile file.

Example fix

// before
pprof.StartCPUProfile(f)
err := commands.NewRunCommand().Execute() // panics/errors: profile already active
// after
pprof.StopCPUProfile()
err := commands.NewRunCommand().Execute()
Defensive patterns

Strategy: try-catch

Validate before calling

if os.Getenv("GOLANGCI_CPU_PROFILE") != "" { // ensure no profile active in-process
	pprof.StopCPUProfile()
}

Try / catch

out, err := cmd.Output()
var pprofErr error
if err != nil {
	if strings.Contains(err.Error(), "can't start CPU profiling") {
		pprofErr = fmt.Errorf("a CPU profile is already active; stop it or drop --cpu-profile: %w", err)
	}
}

Prevention

When it happens

Trigger: Running golangci-lint with --cpu-profile set while another CPU profile was already started in the same process (pprof allows only one active CPU profile).

Common situations: Test harnesses or wrapper scripts that start profiling themselves and then invoke the profiling-enabled lint run in-process; double invocation of persistentPreRunE in custom command compositions.

Related errors


AI-assisted analysis of golangci/golangci-lint@ed7a235d2d (2026-09-02). Data as JSON: /api/errors/dc5130dd2b02d24b. Report an issue: GitHub.