golangci/golangci-lint · error
file %s open: %w
Error message
file %s open: %w
What it means
After findConfigurationFile succeeds, LoadConfiguration opens the located file with os.Open; this wrapper reports 'file %s open'. The config path was found in the directory listing but could not be opened for reading, so the wrapped error is a *os.PathError (usually EACCES or a race where the file disappeared).
Source
Thrown at pkg/commands/internal/configuration.go:103
// Version of the module.
// Only for module available through a Go proxy.
Version string `yaml:"version,omitempty"`
// Path to the local module.
// Only for local module.
Path string `yaml:"path,omitempty"`
}
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)View on GitHub (pinned to ed7a235d2d)
Solutions
- Check and fix permissions: chmod +r <configFile> (and ensure parent directories allow traversal)
- Confirm the matched name is a regular readable file, not a directory or broken symlink (ls -la)
- Re-run if a concurrent process may have removed the file between listing and open
- If permissions cannot be relaxed, run the command as a user with read access
Example fix
// before -rw------- 1 ci ci config.yaml # CI user cannot read // after chmod 644 config.yaml
Defensive patterns
Strategy: validation
Validate before calling
if fi, err := os.Stat(configFilePath); err != nil {
return fmt.Errorf("config %s unreadable: %w", configFilePath, err)
} else if !fi.Mode().IsRegular() {
return fmt.Errorf("config %s is not a regular file", configFilePath)
} else if fi.Mode().Perm()&0o400 == 0 {
return fmt.Errorf("config %s has no read permission for current user", configFilePath)
} Try / catch
cfg, err := LoadConfiguration()
if err != nil {
var perr *fs.PathError
if errors.As(err, &perr) && errors.Is(perr, fs.ErrPermission) {
log.Fatalf("config %s: permission denied — chmod +r or run as a user with access", perr.Path)
}
return err
} Prevention
- Commit config files with 644 permissions; avoid restrictive umasks in CI
- Never name a directory like the config file or leave broken symlinks at that name
- Verify the matched file is a regular readable file after discovery
- If running as a different user in CI, confirm it can read the checked-out config
When it happens
Trigger: findConfigurationFile matched the filename but os.Open(configFilePath) failed: no read permission on the file, it is a directory or symlink to something unreadable, or it was deleted between listing and opening.
Common situations: Config file committed with 000/600 permissions while CI runs as another user, config checked out with restrictive umask, a directory named like the config file, or a broken symlink named config.yaml.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- create destination file: %w
- open source file: %w
- stat source file: %w
- create destination directory: %w
- copy source to destination: %w
AI-assisted analysis of golangci/golangci-lint@ed7a235d2d (2026-09-02).
Data as JSON: /api/errors/845dc8ba7670296b.
Report an issue: GitHub.