golangci/golangci-lint · error

can't run linter %s

Error message

can't run linter %s

What it means

Runner.Run executes each enabled linter via runLinterSafe inside a timed stage tracker. If a linter returns an error (not a panic), Run joins it into a joined error with the message "can't run linter <name>" and continues with the remaining linters. Linting overall continues; the failure is reported at the end.

Source

Thrown at pkg/lint/runner.go:144

		Log:     log,
	}, nil
}

func (r *Runner) Run(ctx context.Context, linters []*linter.Config) ([]*result.Issue, error) {
	sw := timeutils.NewStopwatch("linters", r.Log)
	defer sw.Print()

	var (
		lintErrors error
		issues     []*result.Issue
	)

	for _, lc := range linters {
		linterIssues, err := timeutils.TrackStage(sw, lc.Name(), func() ([]*result.Issue, error) {
			return r.runLinterSafe(ctx, r.lintCtx, lc)
		})
		if err != nil {
			lintErrors = errors.Join(lintErrors, fmt.Errorf("can't run linter %s", lc.Linter.Name()), err)
			r.Log.Warnf("Can't run linter %s: %v", lc.Linter.Name(), err)

			continue
		}

		issues = append(issues, linterIssues...)
	}

	return r.processLintResults(issues), lintErrors
}

func (r *Runner) runLinterSafe(ctx context.Context, lintCtx *linter.Context,
	lc *linter.Config,
) (ret []*result.Issue, err error) {
	defer func() {
		if panicData := recover(); panicData != nil {
			if pe, ok := panicData.(*errorutil.PanicError); ok {
				err = fmt.Errorf("%s: %w", lc.Name(), pe)

View on GitHub (pinned to ed7a235d2d)

Solutions

  1. Check the accompanying Warnf log "Can't run linter <name>: <err>" for the underlying cause
  2. Run golangci-lint with `-v` to see per-linter stage output and isolate the failing linter
  3. Run the failing linter alone (`golangci-lint run --enable-only <name>`) to reproduce and fix its specific issue
  4. Increase `run.timeout`, or exclude problematic files/dirs via `linters.exclusions.rules` if a specific file triggers the failure

Example fix

// before (.golangci.yml)
run:
  timeout: 1m   # large repo exceeds this
// after
run:
  timeout: 10m
Defensive patterns

Strategy: try-catch

Validate before calling

// Isolate the failing linter before a full run:
// golangci-lint run --enable-only <name> ./...
// go vet ./...  # many runtime linter failures mirror vet/parse errors

Try / catch

lintErrors, err := runLinterSafe(ctx, lintCtx, lc)
if err != nil {
    var joined interface{ Unwrap() []error }
    if errors.As(err, &joined) {
        for _, e := range errors.Unwrap(err).([]error) {
            log.Warnf("linter failed: %v", e) // handle per-linter cause
        }
    }
    continue // Run() already continues to next linter
}

Prevention

When it happens

Trigger: Any non-panic error returned from a linter's analysis pass in runLinterSafe: analyzer reporting fatal diagnostics, linter failing to parse invalid Go syntax, running out of memory/timeout for huge packages, or a linter's internal dependency failing on the given codebase.

Common situations: Linter choking on generated or malformed code; timeout (`run.timeout`) hitting on large repos; a newly updated linter version incompatible with the codebase; linter requiring CGO while CGO_ENABLED=0.

Related errors


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