golangci/golangci-lint · error

YAML decoding: %w

Error message

YAML decoding: %w

What it means

LoadConfiguration decodes the opened file with yaml.NewDecoder(file).Decode(&cfg) into a Configuration struct; this wrapper reports 'YAML decoding'. The file exists and opened fine but its content is not valid YAML, or is an empty stream / violates struct requirements during unmarshalling.

Source

Thrown at pkg/commands/internal/configuration.go:112

func LoadConfiguration() (*Configuration, error) {
	configFilePath, err := findConfigurationFile()
	if err != nil {
		return nil, fmt.Errorf("file %s not found: %w", configFilePath, err)
	}

	file, err := os.Open(configFilePath)
	if err != nil {
		return nil, fmt.Errorf("file %s open: %w", configFilePath, err)
	}

	defer func() { _ = file.Close() }()

	var cfg Configuration

	err = yaml.NewDecoder(file).Decode(&cfg)
	if err != nil {
		return nil, fmt.Errorf("YAML decoding: %w", err)
	}

	return &cfg, nil
}

func findConfigurationFile() (string, error) {
	entries, err := os.ReadDir(".")
	if err != nil {
		return "", fmt.Errorf("read directory: %w", err)
	}

	for _, entry := range entries {
		ext := filepath.Ext(entry.Name())

		switch strings.ToLower(strings.TrimPrefix(ext, ".")) {
		case "yml", "yaml", "json":
			if isConf(ext, entry.Name()) {
				return entry.Name(), nil

View on GitHub (pinned to ed7a235d2d)

Solutions

  1. Validate the file with a YAML linter/parser (yamllint or python -c 'import yaml,sys; yaml.safe_load(open(sys.argv[1]))') to get the exact line
  2. Fix indentation to spaces only — YAML forbids tabs; ensure 'key: value' has a space after the colon
  3. If the file is intentionally empty, populate required fields (e.g. destination, plugins) — empty streams error on Decode into a struct
  4. Compare fields against the Configuration struct of your installed version; remove/rename stale keys after upgrading
  5. The wrapped error includes line/column — jump there and correct the syntax

Example fix

// before
plugins:
	- path: ./x   # tab indentation
// after
plugins:
  - path: ./x   # spaces only
Defensive patterns

Strategy: validation

Validate before calling

data, err := os.ReadFile(configFilePath)
if err != nil { return err }
if len(strings.TrimSpace(string(data))) == 0 {
    return fmt.Errorf("config %s is empty; populate required fields", configFilePath)
}
var probe map[string]any
if err := yaml.Unmarshal(data, &probe); err != nil {
    return fmt.Errorf("invalid YAML in %s: %w", configFilePath, err)
}

Try / catch

cfg, err := LoadConfiguration()
if err != nil {
    var yerr *yaml.TypeError
    switch {
    case errors.As(err, &yerr):
        log.Fatalf("config field type mismatch: %v — align fields with the Configuration schema for your version", yerr)
    case strings.Contains(err.Error(), "YAML decoding"):
        log.Fatalf("config is not valid YAML: %v — run yamllint and fix the reported line", err)
    default:
        return err
    }
}

Prevention

When it happens

Trigger: yaml.Decode fails on malformed YAML (bad indentation, tabs, duplicate keys with strict settings), an empty config file (io.EOF from decoding an empty stream), or an incompatible scalar type for a Configuration field (e.g. string where an int is expected).

Common situations: Hand-edited config introducing tab indentation or missing space after a colon, config file left empty after a failed merge, pasted YAML with smart quotes, or schema drift after upgrading the tool to a version with new/changed field types.

Related errors


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