golangci/golangci-lint · error

can't load config: %w

Error message

can't load config: %w

What it means

The config command's preRunE builds a default config and uses config.NewLintersLoader to load and process the user's configuration. Any failure from loader.Load(config.LoadOptions{}) — parsing, validation, or linters-settings resolution — is wrapped as "can't load config: %w".

Source

Thrown at pkg/commands/config.go:97

	pathFlagSet := pathCommand.Flags()
	pathFlagSet.BoolVar(&c.pathOpts.JSON, "json", false, color.GreenString("Display as JSON"))

	c.cmd = configCmd

	return c
}

func (c *configCommand) preRunE(cmd *cobra.Command, args []string) error {
	// The command doesn't depend on the real configuration.
	// It only needs to know the path of the configuration file.
	cfg := config.NewDefault()

	loader := config.NewLintersLoader(c.log.Child(logutils.DebugKeyConfigReader), c.viper, cmd.Flags(), c.opts, cfg, args)

	err := loader.Load(config.LoadOptions{})
	if err != nil {
		return fmt.Errorf("can't load config: %w", err)
	}

	return nil
}

func (c *configCommand) executePath(cmd *cobra.Command, _ []string) error {
	usedConfigFile := c.getUsedConfig()

	if c.pathOpts.JSON {
		abs, err := filepath.Abs(usedConfigFile)
		if err != nil {
			return err
		}

		return json.NewEncoder(cmd.OutOrStdout()).Encode(map[string]string{
			"path":         usedConfigFile,
			"absolutePath": abs,
		})

View on GitHub (pinned to ed7a235d2d)

Solutions

  1. Inspect the wrapped %w error for the precise problem (line number in YAML, unknown key, unknown linter) and fix the config accordingly
  2. Run the config verify subcommand (JSON Schema validation) to pinpoint invalid config elements
  3. Confirm the config file path is correct and readable from the current working directory
  4. If the config comes from an older release, migrate it to the current schema (check the changelog for renamed options)

Example fix

# before (.golangci.yml)
linters:
  enable:
    - lll
  settings:
    lll: { lin-length: 120 }   # unknown key

# after
linters:
  enable:
    - lll
settings:
  lll:
    line-length: 120
Defensive patterns

Strategy: validation

Validate before calling

func validateConfigBeforeLoad(path string) error {
    data, err := os.ReadFile(path)
    if err != nil {
        return fmt.Errorf("config unreadable: %w", err)
    }
    var v map[string]any
    if err := yaml.Unmarshal(data, &v); err != nil {
        return fmt.Errorf("config is not valid YAML: %w", err)
    }
    return nil // then run `golangci-lint config verify` for schema-level checks
}

Type guard

var loadErr *config.LoadError // or inspect wrapped causes
if errors.As(err, &target) {
    switch {
    case errors.Is(err, os.ErrNotExist): // wrong path
    case strings.Contains(err.Error(), "unknown"): // unknown linter/key
    }
}

Try / catch

if err := loader.Load(config.LoadOptions{}); err != nil {
    if strings.Contains(err.Error(), "unknown") || strings.Contains(err.Error(), "unmarshal") {
        log.Fatalf("config problem, run 'golangci-lint config verify' for details: %v", err)
    }
    return fmt.Errorf("can't load config: %w", err)
}

Prevention

When it happens

Trigger: Invoking any config subcommand (e.g. `config path`) whose preRunE calls loader.Load, when the YAML/JSON config file is malformed or references unknown linters/settings.

Common situations: Typo in a config key or linter name; invalid YAML/JSON syntax (bad indentation, tabs); config file path wrong or unreadable; config written for an older/newer version with incompatible options.

Related errors


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