golangci/golangci-lint · error
can't unmarshal config by viper (flags, file): %w
Error message
can't unmarshal config by viper (flags, file): %w
What it means
After successfully reading a config file, the loader unmarshals the merged view (flags + file) into the config struct with a custom decoder hook. A type or shape mismatch between the merged configuration and the struct produces this wrapped error.
Source
Thrown at pkg/config/base_loader.go:178
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)
}
if l.cfg.IsInternalTest() { // just for testing purposes: to detect config file usage
_, _ = fmt.Fprintln(logutils.StdOut, "test")
os.Exit(exitcodes.Success)
}
return nil
}
func (l *BaseLoader) setConfigDir() error {
usedConfigFile := l.viper.ConfigFileUsed()
if usedConfigFile == "" {
return nil
}
if usedConfigFile == os.Stdin.Name() {
usedConfigFile = ""View on GitHub (pinned to ed7a235d2d)
Solutions
- Read the wrapped error: viper names the field that failed to decode and the found/expected types
- Fix the value's type/shape in the config file (lists need `- item` entries, ints unquoted, etc.)
- Check the docs for the current key names — deprecated keys may need migration
- Bisect by commenting out config sections until unmarshal succeeds
Example fix
# before
issues:
exclude-dirs: vendor
# after
issues:
exclude-dirs:
- vendor Defensive patterns
Strategy: validation
Validate before calling
var raw map[string]any
data, _ := os.ReadFile(".golangci.yml")
if err := yaml.Unmarshal(data, &raw); err != nil {
log.Fatal(err)
}
if v, ok := raw["issues"].(map[string]any); ok {
if ed, ok := v["exclude-dirs"].(string); ok {
log.Fatalf("exclude-dirs must be a list, got string: %q", ed)
}
} Prevention
- After upgrading golangci-lint, migrate renamed/deprecated config keys
- Ensure list-typed options are YAML sequences, not scalars
- Verify nesting: linter options go under linters-settings, exclusions under issues/linters.exclusions
- Comment out config sections and bisect when unmarshal errors appear
When it happens
Trigger: A config file (or flag) sets a key whose value type doesn't match the config struct field — e.g. a string where a []string is expected, a nested map where a scalar is expected, or a deprecated/renamed key with the wrong shape.
Common situations: Upgrading golangci-lint after renaming/moving config keys; copy-pasting config from another tool; putting a single value where a list is required; wrong nesting level (e.g. option under `linters` instead of `linters-settings`).
Related errors
- can't unmarshal config by viper (flags): %w
- can't read viper config: %w
- the configuration contains invalid elements
- unsupported configuration format
- the configuration contains invalid elements
AI-assisted analysis of golangci/golangci-lint@ed7a235d2d (2026-09-02).
Data as JSON: /api/errors/c8ae0508bf353c19.
Report an issue: GitHub.