golangci/golangci-lint · error
open file: %w
Error message
open file: %w
What it means
fakeloader.Load wraps the error from os.Open(srcPath) when it cannot open the configuration file for reading. This loader preserves original key casing (unlike Viper, which lowercases keys), so it is used to re-read the config during migration and tests. The error means the source configuration file could not be opened at all.
Source
Thrown at pkg/commands/internal/migrate/fakeloader/fakeloader.go:18
package fakeloader
import (
"fmt"
"os"
"github.com/go-viper/mapstructure/v2"
"github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/parser"
"github.com/golangci/golangci-lint/v2/pkg/config"
)
// Load is used to keep case of configuration.
// Viper serialize raw map keys in lowercase, this is a problem with the configuration of some linters.
func Load(srcPath string, old any) error {
file, err := os.Open(srcPath)
if err != nil {
return fmt.Errorf("open file: %w", err)
}
defer func() { _ = file.Close() }()
raw := map[string]any{}
err = parser.Decode(file, raw)
if err != nil {
return err
}
// NOTE: this is inspired by viper internals.
cc := &mapstructure.DecoderConfig{
Result: old,
WeaklyTypedInput: true,
DecodeHook: config.DecodeHookFunc(),
}
View on GitHub (pinned to ed7a235d2d)
Solutions
- Verify the configuration file path passed via --config or the default (.golangci.yml) exists: ls -l <path>.
- Check read permissions on the file and its parent directories.
- If running in CI/containers, ensure the config file is mounted/copied into the workspace.
- Confirm you are running the command from the directory where the config resides.
Example fix
// before
loader.Load(".golangci.yaml") // file is actually .golangci.yml
// after
if _, err := os.Stat(".golangci.yml"); err != nil {
log.Fatal("config file not found: ", err)
}
loader.Load(".golangci.yml") Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(cfgPath)
if err != nil { /* file missing */ }
if info.IsDir() { /* path is a directory */ } Try / catch
if err := loader.Load(srcPath, &old); err != nil {
if errors.Is(err, fs.ErrNotExist) {
// fall back to default config or abort with friendly message
}
return err
} Prevention
- Confirm the config path with os.Stat before invoking Load.
- Use `golangci-lint config path` to locate the effective config.
- Mount/copy the config file in containers and CI.
When it happens
Trigger: Calling Load with a srcPath that does not exist, points to a directory, or lacks read permissions; called from testFile and persistentPreRunE during `golangci-lint migrate`.
Common situations: Typo in the --config path, config file deleted or moved before migrating, running in a container where the config path was not mounted, or insufficient file permissions.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- file %s not found: %w
- configuration file not found
- hash plugin directory: %w
- file %s open: %w
- YAML decoding: %w
AI-assisted analysis of golangci/golangci-lint@ed7a235d2d (2026-09-02).
Data as JSON: /api/errors/9d4eb4b89fe55d78.
Report an issue: GitHub.