{"record":{"id":"9d4eb4b89fe55d78","repo":"golangci/golangci-lint","slug":"open-file-w","errorCode":null,"errorMessage":"open file: %w","messagePattern":"open file: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/commands/internal/migrate/fakeloader/fakeloader.go","lineNumber":18,"sourceCode":"package fakeloader\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/go-viper/mapstructure/v2\"\n\n\t\"github.com/golangci/golangci-lint/v2/pkg/commands/internal/migrate/parser\"\n\t\"github.com/golangci/golangci-lint/v2/pkg/config\"\n)\n\n// Load is used to keep case of configuration.\n// Viper serialize raw map keys in lowercase, this is a problem with the configuration of some linters.\nfunc Load(srcPath string, old any) error {\n\tfile, err := os.Open(srcPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"open file: %w\", err)\n\t}\n\n\tdefer func() { _ = file.Close() }()\n\n\traw := map[string]any{}\n\n\terr = parser.Decode(file, raw)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// NOTE: this is inspired by viper internals.\n\tcc := &mapstructure.DecoderConfig{\n\t\tResult:           old,\n\t\tWeaklyTypedInput: true,\n\t\tDecodeHook:       config.DecodeHookFunc(),\n\t}\n","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/golangci/golangci-lint/blob/ed7a235d2d771152056fdc142a9855567c5796a9/pkg/commands/internal/migrate/fakeloader/fakeloader.go#L1-L36","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","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."],"exampleFix":"// before\nloader.Load(\".golangci.yaml\") // file is actually .golangci.yml\n// after\nif _, err := os.Stat(\".golangci.yml\"); err != nil {\n    log.Fatal(\"config file not found: \", err)\n}\nloader.Load(\".golangci.yml\")","handlingStrategy":"validation","validationCode":"info, err := os.Stat(cfgPath)\nif err != nil { /* file missing */ }\nif info.IsDir() { /* path is a directory */ }","typeGuard":null,"tryCatchPattern":"if err := loader.Load(srcPath, &old); err != nil {\n    if errors.Is(err, fs.ErrNotExist) {\n        // fall back to default config or abort with friendly message\n    }\n    return err\n}","preventionTips":["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."],"tags":["go","config","file-not-found","io"],"backgroundTag":"file-not-found","analyzedSha":"ed7a235d2d771152056fdc142a9855567c5796a9","analyzedAt":"2026-09-02T18:47:33.865Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}