golangci/golangci-lint · error

can't unmarshal config by viper (flags): %w

Error message

can't unmarshal config by viper (flags): %w

What it means

When viper cannot find any config file (viper.ConfigFileNotFoundError), the loader falls back to unmarshaling configuration from flags only into the settings struct. If viper.Unmarshal fails on the flag-only view, this error is returned and loading aborts.

Source

Thrown at pkg/config/base_loader.go:162

	}

	// find home directory for global config
	if home, err := homedir.Dir(); err != nil {
		l.log.Warnf("Can't get user's home directory: %v", err)
	} else if !slices.Contains(searchPaths, home) {
		searchPaths = append(searchPaths, home)
	}

	return searchPaths
}

func (l *BaseLoader) parseConfig() error {
	if err := l.viper.ReadInConfig(); err != nil {
		if _, ok := errors.AsType[viper.ConfigFileNotFoundError](err); ok {
			// Load configuration from flags only.
			err = l.viper.Unmarshal(l.cfg, customDecoderHook())
			if err != nil {
				return fmt.Errorf("can't unmarshal config by viper (flags): %w", err)
			}

			return nil
		}

		return fmt.Errorf("can't read viper config: %w", err)
	}

	err := l.setConfigDir()
	if err != nil {
		return err
	}

	// Load configuration from all sources (flags, file).
	if err := l.viper.Unmarshal(l.cfg, customDecoderHook()); err != nil {
		return fmt.Errorf("can't unmarshal config by viper (flags, file): %w", err)
	}

View on GitHub (pinned to ed7a235d2d)

Solutions

  1. Check the wrapped error for the offending field and fix the flag value type/format
  2. Validate flags against `golangci-lint run --help` for expected value formats
  3. Remove or correct the recently added flag(s) to isolate the culprit
  4. Use a config file instead of many flags so values are type-checked in one place

Example fix

// before
golangci-lint run --timeout=abc
// after
golangci-lint run --timeout=5m
Defensive patterns

Strategy: validation

Validate before calling

// Validate flag-only values before running
args := []string{"--timeout=5m", "--out-format=line-number"}
for _, a := range args {
	if strings.Contains(a, "timeout=") {
		if _, err := time.ParseDuration(strings.TrimPrefix(a, "--timeout=")); err != nil {
			log.Fatalf("bad flag value: %s", a)
		}
	}
}

Prevention

When it happens

Trigger: No config file found (or config search disabled) AND a flag-set value cannot be decoded into the config struct via the custom decoder hook — typically a flag value of the wrong type/format.

Common situations: Passing values with wrong types via flags (e.g. non-integer for a duration/int option); typo'd flag mapped onto a struct field with an incompatible type; malformed map/slice syntax in flag values.

Related errors


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