golangci/golangci-lint · error

is a formatter

Error message

%s is a formatter

What it means

Linters.validateNoFormatters rejects any name in linters.enable or linters.disable that is actually a formatter. In golangci-lint v2, formatters were split out of linters, so configuring e.g. 'gofmt' under linters is an error rather than silently accepted.

Solutions

  1. Move formatter names from linters.enable to formatters.enable
  2. Remove formatter names from linters.disable and use formatters settings instead
  3. Run 'golangci-lint migrate' to auto-convert a v1 config to v2

Example fix

# before
linters:
  enable:
    - gofmt
    - revive
# after
linters:
  enable:
    - revive
formatters:
  enable:
    - gofmt
Defensive patterns

Strategy: validation

Validate before calling

formatterNames := getAllFormatterNames()
for _, n := range slices.Concat(cfg.Linters.Enable, cfg.Linters.Disable) {
	if slices.Contains(formatterNames, n) {
		return fmt.Errorf("%s is a formatter; move it to formatters", n)
	}
}

Try / catch

if err := linters.Validate(); err != nil { log.Fatalf("linters config: %v", err) }

Prevention

When it happens

Trigger: v1-style config where gofmt/goimports/gofumpt etc. are listed under linters.enable or linters.disable; running golangci-lint v2 on an unmigrated config.

Common situations: Upgrading from golangci-lint v1 to v2 without running the migration; copy-pasting old configs; disabling a formatter via linters.disable.

Related errors


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

Appendix: source

Thrown at pkg/config/linters.go:44

func (l *Linters) Validate() error {
	validators := []func() error{
		l.Exclusions.Validate,
		l.validateNoFormatters,
	}

	for _, v := range validators {
		if err := v(); err != nil {
			return err
		}
	}

	return nil
}

func (l *Linters) validateNoFormatters() error {
	for _, n := range slices.Concat(l.Enable, l.Disable) {
		if slices.Contains(getAllFormatterNames(), n) {
			return fmt.Errorf("%s is a formatter", n)
		}
	}

	return nil
}

func getAllFormatterNames() []string {
	return []string{"gci", "gofmt", "gofumpt", "goimports", "golines", "swaggo"}
}

View on GitHub (pinned to ed7a235d2d)